NAVER CLOUD PLATFORM & Photon PUN2 유니티 멀티게임 만들기 Webinar 2탄

 



AllCallbackManager.cs 소스입니다


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


public class AllCallbackManager : MonoBehaviourPunCallbacks
{
public override void OnConnected()
{
// 연결 성공

//PhotonNetwork.ConnectUsingSettings();
}

public override void OnDisconnected(DisconnectCause cause)
{
// 연결 끊김

//PhotonNetwork.Disconnect();
}

public override void OnConnectedToMaster()
{
// 마스터서버 연결
}


public override void OnJoinedLobby()
{
// 로비 참가

//PhotonNetwork.JoinLobby();
}

public override void OnLeftLobby()
{
// 로비 나감

//PhotonNetwork.LeaveLobby();
}

public override void OnCreatedRoom()
{
// 방 만들기

//PhotonNetwork.CreateRoom("room", new RoomOptions { MaxPlayers = 2 }, null);
//PhotonNetwork.JoinOrCreateRoom("room", new RoomOptions { MaxPlayers = 2 }, null);
}

public override void OnCreateRoomFailed(short returnCode, string message)
{
// 방 만들기 실패
}

public override void OnJoinedRoom()
{
// 방 참가

//PhotonNetwork.JoinRoom("room");
//PhotonNetwork.JoinRandomRoom();
}

public override void OnJoinRoomFailed(short returnCode, string message)
{
// 방 참가 실패
}

public override void OnJoinRandomFailed(short returnCode, string message)
{
// 방 랜덤참가 실패
}

public override void OnLeftRoom()
{
// 방 나감

//PhotonNetwork.LeaveRoom();
}

public override void OnLobbyStatisticsUpdate(List<TypedLobbyInfo> lobbyStatistics)
{
// 여러 로비를 사용하고 싶으면 PhotonServerSettings - Lobby Statistics 활성화
// 마스터서버에서 로비들의 정보를 볼 수 있음

//PhotonNetwork.JoinLobby(new TypedLobby("dduck", LobbyType.Default));
//for (int i = 0; i < lobbyStatistics.Count; i++)
//{
// LogText.text += lobbyStatistics[i].Name + ", " + lobbyStatistics[i].PlayerCount + "\n";
//}
}

public override void OnMasterClientSwitched(Player newMasterClient)
{
// 방에 있을 때, 방장이 바뀔시

//PhotonNetwork.SetMasterClient(PhotonNetwork.PlayerList[0]);
}


//List<RoomInfo> myList = new List<RoomInfo>();

public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
// 로비에 있을 때, 방 리스트 업데이트 시

//int roomCount = roomList.Count;
//for (int i = 0; i < roomCount; i++)
//{
// if (!roomList[i].RemovedFromList)
// {
// if (!myList.Contains(roomList[i])) myList.Add(roomList[i]);
// else myList[myList.IndexOf(roomList[i])] = roomList[i];
// }
// else if (myList.IndexOf(roomList[i]) != -1) myList.RemoveAt(myList.IndexOf(roomList[i]));
//}
}

public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
// 방에 있을 때, 방 태그 변경시

//PhotonNetwork.CurrentRoom.SetCustomProperties(new Hashtable { { "RoomTag", "tag" } });
}

public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
{
// 방에 있을 때, 플레이어의 태그 변경시

//PhotonNetwork.PlayerList[0].SetCustomProperties(new Hashtable { { "PlayerTag", "tag" } });
}

public override void OnPlayerEnteredRoom(Player newPlayer)
{
// 방에 있을 때, 새로운 플레이어가 들어옴
}

public override void OnPlayerLeftRoom(Player otherPlayer)
{
// 방에 있을 때, 다른 플레이어가 나감
}
}












NetworkManager.cs 소스입니다



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


public class NetworkManager : MonoBehaviourPunCallbacks
{
[Header("DisconnectPanel")]
public GameObject DisconnectPanel;
public InputField NicknameInput;

[Header("RoomPanel")]
public GameObject RoomPanel;
public GameObject InitGameBtn, RollBtn;
public Text[] NicknameTexts;
public GameObject[] ArrowImages;
public Text[] MoneyTexts;
public Text LogText;

[Header("Board")]
public DiceScript diceScript;
public PlayerScript[] Players;
public Transform[] Pos;


int myNum, turn;
PhotonView PV;


void Start()
{
#if (!UNITY_ANDROID)
Screen.SetResolution(960, 540, false);
#endif
PV = photonView;
}

public void Connect() 
{
PhotonNetwork.LocalPlayer.NickName = NicknameInput.text;
PhotonNetwork.ConnectUsingSettings();
}

public override void OnConnectedToMaster()
{
PhotonNetwork.JoinOrCreateRoom("MyRoom", new RoomOptions { MaxPlayers = 2 }, null);
}

void ShowPanel(GameObject CurPanel) 
{
DisconnectPanel.SetActive(false);
RoomPanel.SetActive(false);

CurPanel.SetActive(true);
}

bool master() 
{
return PhotonNetwork.LocalPlayer.IsMasterClient;
}

public override void OnJoinedRoom()
{
ShowPanel(RoomPanel);
if (master()) InitGameBtn.SetActive(true);
}

public void InitGame() 
{
if (PhotonNetwork.CurrentRoom.PlayerCount != 2) return;

RollBtn.SetActive(true);
InitGameBtn.SetActive(false);
PV.RPC("InitGameRPC", RpcTarget.AllViaServer);

}

[PunRPC]
void InitGameRPC() 
{
print("게임시작");
for (int i = 0; i < 2; i++)
{
NicknameTexts[i].text = PhotonNetwork.PlayerList[i].NickName;

if (PhotonNetwork.PlayerList[i] == PhotonNetwork.LocalPlayer)
myNum = i;
}
}


public void Roll() 
{
PV.RPC("RollRPC", RpcTarget.MasterClient);
}

[PunRPC]
void RollRPC() 
{
StartCoroutine(RollCo());
}

[PunRPC]
void EndRollRPC(int money0, int money1)
{
turn = turn == 0 ? 1 : 0;

for (int i = 0; i < 2; i++)
ArrowImages[i].SetActive(i == turn);

RollBtn.SetActive(myNum == turn);

MoneyTexts[0].text = money0.ToString();
MoneyTexts[1].text = money1.ToString();

if (money0 <= 0 || money1 >= 300) LogText.text = NicknameTexts[1].text + "이 승리하셨습니다";
else if (money1 <= 0 || money0 >= 300) LogText.text = NicknameTexts[0].text + "이 승리하셨습니다";
}

IEnumerator RollCo() 
{
// 방장만 함수 호출
yield return StartCoroutine(diceScript.Roll());
yield return StartCoroutine(Players[turn].Move(diceScript.num));
yield return new WaitForSeconds(0.2f);

PV.RPC("EndRollRPC", RpcTarget.AllViaServer, Players[0].money, Players[1].money);
}
}











PlayerScript.cs 소스입니다




using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerScript : MonoBehaviour
{
    public int curPos, myNum, money;
    public NetworkManager NM;
    public PlayerScript otherPlayer;

    public IEnumerator Move(int diceNum) 
    {
        // 갈 길 배열 만들기
        int[] movePos = new int[diceNum];
        bool isZero = false;
        for (int i = 0; i < movePos.Length; i++)
        {
            int plusNum = curPos + i + 1;
            if (plusNum > 23)
            {
                isZero = true;
                plusNum -= 24;
            }
            movePos[i] = plusNum;
        }

        // 부드럽게 이동
        for (int i = 0; i < movePos.Length; i++)
        {
            Vector3 targetPos = NM.Pos[movePos[i]].position;
            while (true)
            {
                yield return null;
                transform.position = Vector3.MoveTowards(transform.position, targetPos, Time.deltaTime * 7);
                if (transform.position == targetPos) break;
            }
        }

        if (isZero)
        {
            money += 30;
            print(myNum + "이 30을 벌었다");
        }

        curPos = movePos[movePos.Length - 1];
        NM.Pos[curPos].GetComponent<GroundScript>().TypeSwitch(this, otherPlayer);
    }
}











DiceScript.cs 소스입니다



using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DiceScript : MonoBehaviour
{
    public Rigidbody RB;
    public Transform[] Nums;
    public int num;

    public IEnumerator Roll() 
    {
        yield return null; 
        transform.position = new Vector3(0, 4, 0);
        transform.localEulerAngles = new Vector3(Random.Range(-90f, 90f), Random.Range(-90f, 90f), Random.Range(-90f, 90f));
        RB.angularVelocity = Random.insideUnitSphere * Random.Range(-1000, 1000);

        yield return new WaitForSeconds(3);
        while (true)
        {
            yield return null;
            if (RB.velocity.sqrMagnitude < 0.001f) break;
        }

        for (int i = 0; i < Nums.Length; i++)
        {
            if (Nums[i].position.y > 1)
            {
                num = i + 1;
                break;
            }
        }
    }
}











GroundScript.cs 소스입니다



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

public class GroundScript : MonoBehaviourPun
{
public enum GroundType { GROUND, GOLDKEY, START };
public GroundType groundType;
public int price, owner;

PhotonView PV;
TextMesh PriceText;
GameObject[] Cubes;
int[] goldKeyMoneys = new int[6] { -20, -10, 0, 10, 20, 30 };


void Start()
{
PV = photonView;
if (groundType == GroundType.GROUND)
{
PriceText = GetComponentInChildren<TextMesh>();
Cubes = new GameObject[2] { transform.GetChild(1).gameObject, transform.GetChild(2).gameObject };
}
}

[PunRPC]
void CubeRPC(int myNum)
{
Cubes[myNum].SetActive(true);
}

[PunRPC]
void AddPriceRPC()
{
price += 10;
PriceText.text = price.ToString();
}


public void TypeSwitch(PlayerScript curPlayer, PlayerScript otherPlayer) 
{
if (groundType == GroundType.GROUND)
{
GroundOwner(curPlayer, otherPlayer);
PV.RPC("AddPriceRPC", RpcTarget.AllViaServer);
}

else if (groundType == GroundType.GOLDKEY) 
{
int addmoney = goldKeyMoneys[Random.Range(0, goldKeyMoneys.Length)];
curPlayer.money += addmoney;
print(curPlayer.myNum + "이 " + addmoney + "을 벌었다");
}
}


void GroundOwner(PlayerScript curPlayer, PlayerScript otherPlayer)
{
int myNum = curPlayer.myNum;

// 빈 땅을 밞음
if (owner == -1)
{
curPlayer.money -= price;
print(myNum + "이 " + price + "을 잃었다");

owner = myNum;
PV.RPC("CubeRPC", RpcTarget.AllViaServer, myNum);
}

// 남의 땅을 밞음
else if (owner != myNum)
{
curPlayer.money -= price;
otherPlayer.money += price;
print(myNum + "이 " + price + "을 잃었다");
print(otherPlayer.myNum + "이 " + price + "을 벌었다");
}
}
}