[Photon] 방 입장 및 레디 상태 추가
이번에는 바로 게임을 시작하는 것보다.
방에 입장을 해서 레디를 한 후 게임을 시작하는 것이 유저 입장에선 준비 할 시간이 된다고 생각을 하여서 구현을 하게 되었습니다.
닉네임 부분은 유저의 닉네임을 가져오고, 레디는 레디 버튼을 누르게 된다면 레디가 되도록 하였습니다.
방은 Lobby Scene에서 방을 만들게 된다면 Scene이동 보단 Canvas의 On/Off로 구현을 하였고, Scroll view로 작업을 하였습니다.
public void Start() {
if (PlayerPrefs.HasKey("NickName"))
PhotonNetwork.NickName = PlayerPrefs.GetString("NickName");
PhotonNetwork.ConnectUsingSettings();
}
RoomManager부터 수정을 한다면, 닉네임을 정확하게 불러왔는지 미지수니깐 닉네임을 확실하게 불러오고 연결을 해줍니다.
void ClearRoomIcons()
{
foreach (Transform child in Roomparent)
{
Destroy(child.gameObject);
}
}
void CreateIcon(Player player, int number)
{
GameObject room = Instantiate(Resources.Load<GameObject>("UserIcon"));
room.transform.SetParent(Roomparent);
room.GetComponent<RoomNickNameManager>().SetNickNameText(player.NickName, number);
}
처음에 만들었던 UserIcon을 삭제하거나 추가하는 함수입니다.
public override void OnJoinedRoom() {
EnterRoom(PhotonNetwork.IsMasterClient ? "Wait" : "Ready");
ClearRoomIcons();
foreach (var player in PhotonNetwork.PlayerList)
{
CreateIcon(player, player.ActorNumber);
}
if (PhotonNetwork.IsMasterClient) AddData("PlayerReady", PhotonNetwork.LocalPlayer.ActorNumber, true); // 방장은 레디상태
}
마스터 클라이언트면 가장 먼저 wait또는 Ready라고 버튼 text에 적히게 하고, 한번 방에 Icon을 Clear를 해줍니다.
만약에 겹쳐서 들어올 경우 처리를 해주어야 하니 플레이어 수 만큼 아이콘을 만들어줍니다.
또한 방장은 항상 준비상태로 설정을 해주었습니다.
public override void OnPlayerEnteredRoom(Player newPlayer) => CreateIcon(newPlayer, newPlayer.ActorNumber); // 새로운 유저 입장
새로운 유저가 들어오면 아이콘을 생성을 해줍니다.
public void SetNickNameText(string nickName, int number) { NickName.text = nickName; UserNumber = number; }
public int GetUserNumber() => UserNumber;
public void SetReady(bool b) => Ready.gameObject.SetActive(b);
위는 NickNameManager입니다. UserIcon에 넣었습니다.
새로운 닉네임을 지정할때 닉네임과 유저 로컬 번호를 저장하게 하였습니다.
그 이유는 나중에 UI 업데이트를 한다고 하였을 때 유저 번호에 따른 아이콘들을 다 업데이트 해주기 위해서입니다.
public override void OnPlayerEnteredRoom(Player newPlayer) => AddData("PlayerReady", newPlayer.ActorNumber, false);
public override void OnPlayerLeftRoom(Player leftPlayer) => RemoveData("PlayerReady", leftPlayer.ActorNumber);
새로운 유저가 입장하면 PlayerReady라는 테이블을 추가해주고
유저가 나가게 된다면 PlayerReady라는 테이블을 제거해줍니다
*마스터 클라이언트만 가능하게 마스터 클라이언트가 받는 함수로만 작업을 하였습니다.
public void OnReadyOrStartButton()
{
if (PhotonNetwork.IsMasterClient)
{
if (Button_text.text.Equals("Go"))
{
Debug.Log("게임 시작");
}
}
else
{
if (Button_text.text.Equals("Ready"))
{
Button_text.text = "UnReady";
photonView.RPC("ChangeReady", RpcTarget.MasterClient, true, PhotonNetwork.LocalPlayer.ActorNumber);
}
else
{
Button_text.text = "Ready";
photonView.RPC("ChangeReady", RpcTarget.MasterClient, false, PhotonNetwork.LocalPlayer.ActorNumber);
}
}
}
버튼에 따라 역할을 넣었고, Ready상태라면 RPC로 Master Client에 보내어 값을 수정해주도록 하였습니다.
[PunRPC]
void ChangeReady(bool b, int number)
{
if (!PhotonNetwork.IsMasterClient) return;
UpdateData("PlayerReady",number, b);
}
넘겨받은 마스터는 해당 정보를 Update해줍니다.
bool AllPlayersReady()
{
var room= PhotonNetwork.CurrentRoom.CustomProperties;
if (!room.ContainsKey("PlayerReady"))
return false; // 아무도 레디 안한 상태
PhotonHashTable table = room["PlayerReady"] as PhotonHashTable;
if (table == null)
return false;
foreach (Player p in PhotonNetwork.PlayerList)
{
if (!table.ContainsKey(p.ActorNumber))
return false; // 아직 레디 안함
if (!(bool)table[p.ActorNumber])
return false; // false거나 잘못된 값
}
return true;
}
모든 유저가 준비상태인지 체크하기 위해서 작성을 하였습니다
테이블에 PlayerReady가 없다면 오류인 방이니 false로 넘겨주고, 플레이어 리스트를 돌면서 Ready를 했는지 체크를 해줍니다.
void UpdateReadyUI()
{
var room = PhotonNetwork.CurrentRoom.CustomProperties;
if (room.ContainsKey("PlayerReady"))
{
PhotonHashTable table =room["PlayerReady"] as PhotonHashTable;
foreach (Transform child in Roomparent)
{
RoomNickNameManager ready = child.GetComponent<RoomNickNameManager>();
if (ready == null || table == null) continue;
int actorNumber = ready.GetUserNumber(); // 유저 정보 가져오기
bool isReady = false;
if (table.ContainsKey(actorNumber)) isReady = (bool)table[actorNumber];
ready.SetReady(isReady);
}
}
}
UI 업데이트 입니다.
RoomParent안의 자식들을 조사하며 RoomNickNameManager를 들고옵니다.
그 이후에 유저 정보를 가져와서 해당 테이블에 유저 정보의 Ready 정보를 가져옵니다.
만약에 true라면 Ready object를 활성화 시켜주고, 아니라면 비활성화 시켜줍니다.
public override void OnRoomPropertiesUpdate(PhotonHashTable propertiesThatChanged)
{
UpdateReadyUI();
if (PhotonNetwork.IsMasterClient)
{
if (propertiesThatChanged.ContainsKey("PlayerReady"))
{
if (AllPlayersReady())
{
Button_text.text = "Go";
}
else
{
if (Button_text.text.Equals("Go")) Button_text.text = "Wait";
}
}
}
}
마지막으로 properties가 update가 됐다는 것은, 레디나 언레디 상태를 만든 것이니
UI를 업데이트 해주고, Master Client인 경우는 모든 유저가 준비가 됐는지 체크를 해주어
모두가 레디가 되었으면 게임 시작을 할 수 있게 합니다.