Tencent Cloud & Photon PUN2 유니티 멀티게임 만들기 Webinar 3탄



ObjectPooler.cs 소스입니다


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;


public class ObjectPooler : MonoBehaviourPun
{
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
public int size;
}

public static ObjectPooler OP;
void Awake() => OP = this;

public List<Pool> pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;


public void PrePoolInstantiate()
{
poolDictionary = new Dictionary<string, Queue<GameObject>>();
foreach (Pool pool in pools)
{
Queue<GameObject> objectPool = new Queue<GameObject>();
for (int i = 0; i < pool.size; i++)
{
GameObject obj = PhotonNetwork.Instantiate(pool.tag, Vector3.zero, Quaternion.identity);
obj.GetComponent<PhotonView>().RPC("SetActiveRPC", RpcTarget.All, false);
objectPool.Enqueue(obj);
}
poolDictionary.Add(pool.tag, objectPool);
}
}

public GameObject PoolInstantiate(string tag, Vector3 position, Quaternion rotation)
{
if (!poolDictionary.ContainsKey(tag))
{
Debug.LogWarning($"Pool with tag {tag} doesn't excist.");
return null;
}

GameObject obj = poolDictionary[tag].Dequeue();
obj.GetComponent<PhotonView>().RPC("SetActiveRPC", RpcTarget.All, true);
obj.transform.position = position;
obj.transform.rotation = rotation;
poolDictionary[tag].Enqueue(obj);

return obj;
}

public void PoolDestroy(GameObject obj)
{
obj.GetComponent<PhotonView>().RPC("SetActiveRPC", RpcTarget.All, false);
}
}
 












PoolScript.cs 소스입니다



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;


public class PoolScript : MonoBehaviourPun
{
[PunRPC]
void SetActiveRPC(bool b) 
{
gameObject.SetActive(b);
}
}














NetworkManager.cs 소스입니다




using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using Photon.Realtime;
using static ObjectPooler;


public class NetworkManager : MonoBehaviourPunCallbacks
{
    public static NetworkManager NM;
    void Awake() => NM = this;

    public List<PlayerScript> players = new List<PlayerScript>();
    public PlayerScript myPlayer;
    public Text LogText;
    [HideInInspector] public PhotonView PV;
    public GameObject CurObj;

    void Start()
    {
        PV = photonView;
        Screen.SetResolution(960, 540, false);
        PhotonNetwork.ConnectUsingSettings();
    }

    public void ShowLog(string log) => LogText.text = log;
    public void SortPlayers() => players.Sort((p1, p2) => p1.actor.CompareTo(p2.actor));

    public override void OnConnectedToMaster() => PhotonNetwork.JoinLobby();
    public override void OnJoinedLobby(){ PhotonNetwork.JoinOrCreateRoom("Room", new RoomOptions { MaxPlayers = 4 }, null);}
    public override void OnJoinedRoom()
    {
        myPlayer = PhotonNetwork.Instantiate("Player", Vector3.zero, Quaternion.identity).GetComponent<PlayerScript>();
}


    void Update()
    {
        if (!PhotonNetwork.InRoom) return;

        if (Input.GetKeyDown(KeyCode.Alpha1))
            OP.PrePoolInstantiate();

        else if (Input.GetKeyDown(KeyCode.Alpha2))
            CurObj = OP.PoolInstantiate("Portion", Vector3.zero, Quaternion.identity);

        else if (Input.GetKeyDown(KeyCode.Alpha3))
            OP.PoolDestroy(CurObj);

        else if (Input.GetKeyDown(KeyCode.Alpha4))
            ++myPlayer.Coin;
    }
}
















PlayerScript.cs 소스입니다



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using static NetworkManager;

public class PlayerScript : MonoBehaviourPun
{
[HideInInspector] public PhotonView PV;
[HideInInspector] public string nick;
[HideInInspector] public int actor;

[SerializeField] int coin;
public int Coin { get => coin; set {  PV.RPC("SetCoinRPC", RpcTarget.AllBufferedViaServer, value); } }
[PunRPC] void SetCoinRPC(int value) => coin = value;

void Start()
    {
PV = photonView;
nick = PV.Owner.NickName;
actor = PV.OwnerActorNr;

NM.players.Add(this);
NM.SortPlayers();
}

void OnDestroy()
{
NM.players.Remove(this);
NM.SortPlayers();
}
}

















PhotonChatGUI.cs 소스입니다


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using Photon.Chat;
using ExitGames.Client.Photon;


public class PhotonChatGUI : MonoBehaviourPunCallbacks, IChatClientListener
{
[HideInInspector] public Vector3 matrixPos = new Vector3(30, 30, 0);
[HideInInspector] public float matrixScale = 1.9f;

ChatClient chatClient;
string stateChatLabel, callbackChatLabel, chatLabel;
string channelName = "채널001", nicknameInput, chatInput;
bool autoJoinChatChannel = true;
Vector2 chatScroll;



void Awake()
{
Screen.SetResolution(1280, 720, false);
matrixScale = Screen.height * 1.9f / 1080f;
chatClient = new ChatClient(this);
}

void Update()
{
chatClient.Service();
}

void OnGUI()
{
GUI.matrix = Matrix4x4.TRS(matrixPos, Quaternion.identity, Vector3.one * matrixScale);
GUILayout.BeginVertical("Box", GUILayout.Width(320));


GUILayout.Label("채팅상태 : " + stateChatLabel);
GUILayout.Label("채팅콜백 : " + callbackChatLabel);
autoJoinChatChannel = GUILayout.Toggle(autoJoinChatChannel, " 자동로비접속");
GUILayout.BeginHorizontal();
GUILayout.Label("닉네임");
nicknameInput = GUILayout.TextField(nicknameInput, GUILayout.Width(150));
GUILayout.EndHorizontal();

GUILayout.Space(10);

GUILayoutOption width = GUILayout.Width(160);
GUILayout.BeginHorizontal();
if (GUILayout.Button("채팅서버 연결", width)) ConnectChatClick();
if (GUILayout.Button("채팅서버 나가기", width)) DisconnectChatClick();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if (GUILayout.Button("채널입장", width)) SubscribeClick();
if (GUILayout.Button("채널나가기", width)) UnsubscribeClick();
GUILayout.EndHorizontal();

GUILayout.Space(10);

chatScroll = GUILayout.BeginScrollView(chatScroll, "Box", GUILayout.MaxHeight(200));
GUILayout.Label(chatLabel);
GUILayout.EndScrollView();

chatInput = GUILayout.TextArea(chatInput);
if (chatInput != null && chatInput.Contains("\n"))
{
if(StringAvailable(chatInput)) Send(chatInput.Trim());
chatInput = "";
}

GUILayout.Label("* 엔터를 치면 보내집니다. (보낼닉네임>>보낼메세지) 로 귓속말이 됩니다");

GUILayout.EndVertical();
}



bool StringAvailable(string s)
{
if (string.IsNullOrWhiteSpace(s)) return false;
return true;
}

public void OnChatStateChange(ChatState state)
{
stateChatLabel = state.ToString();
}

void SetCallbackChatLabel(string s) 
{
callbackChatLabel = s;
}

void ReceiveMessages(string nickName, string msg) 
{
chatLabel += (chatLabel != "" ? "\n" : "") + nickName + " : " + msg;
}

void ReceiveMessages(string msg)
{
chatLabel += (chatLabel != "" ? "\n" : "") + msg;
}



#region 버튼과 콜백
void ConnectChatClick() 
{
if (StringAvailable(nicknameInput))
{
chatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion,
new Photon.Chat.AuthenticationValues(nicknameInput));
}
}

public override void OnConnected()
{
SetCallbackChatLabel("OnConnected");
if (autoJoinChatChannel) SubscribeClick();
}



void DisconnectChatClick()
{
chatClient.Disconnect();
}

public void OnDisconnected()
{
SetCallbackChatLabel("OnDisconnected");
}



void SubscribeClick() 
{
chatClient.Subscribe(new string[] { channelName }, 10);
}

public void OnSubscribed(string[] channels, bool[] results)
{
chatLabel = "";
SetCallbackChatLabel("OnSubscribed");
}



void UnsubscribeClick()
{
chatClient.Unsubscribe(new string[] { channelName });
}

public void OnUnsubscribed(string[] channels)
{
SetCallbackChatLabel("OnUnsubscribed");
}



void Send(string s)
{
if (s.Contains(">>"))
{
string[] ss = s.Split(new string[] { ">>" }, System.StringSplitOptions.None);
chatClient.SendPrivateMessage(ss[0], ss[1]);
}
else chatClient.PublishMessage(channelName, s); 
}

public void OnGetMessages(string channelName, string[] senders, object[] messages)
{
for (int i = 0; i < messages.Length; i++)
{
ReceiveMessages(senders[i], messages[i].ToString());
}
chatScroll.y = 100000;
}

public void OnPrivateMessage(string sender, object message, string channelName)
{
ReceiveMessages(sender + "의 귓속말", message.ToString());
chatScroll.y = 100000;
}
#endregion



public void OnUserSubscribed(string channel, string user) { }
public void OnUserUnsubscribed(string channel, string user) { }
public void OnStatusUpdate(string user, int status, bool gotMessage, object message) { }
public void DebugReturn(DebugLevel level, string message) { }
}