오늘은 슬롯의 캐릭터 이미지와 준비BTN, 시작BTN 등을 구현하였다.
방 정보는 RPC를 통해 마스터 클라이언트가 새로운 클라이언트에게 전달하는 방식으로 처리했다.( CustomRoomProperties에 대해서도 차근차근 익혀나가야겠다. )
이렇게 캐릭터 슬롯을 닫으면 남는 자리에 새로운 플레이어가 들어오게 된다.(방장만 슬롯 컨트롤 가능)
public void CharactorSlotClick(int num)
{
if(PhotonNetwork.IsMasterClient)
{
PV.RPC("ChangeCharactorSlot", RpcTarget.All,num);//빈칸 번호를 넘김
}
}
[PunRPC]
public void ChangeCharactorSlot(int num)
{
if (PlayerBtn[num].image.sprite == O && PlayerName[num]==" ")//만약 열려있고 사람이 안들어와 있다면 닫는거 가능
{
PlayerBtnarr[num] = 1;
PlayerBtn[num].image.sprite = X;
}
else if(PlayerBtn[num].image.sprite == X && PlayerName[num] == " ")
{
PlayerBtnarr[num] = 0;
PlayerBtn[num].image.sprite = O;
}
}
public override void OnJoinedRoom()
{
RoomName.text = PhotonNetwork.CurrentRoom.Name;
RoomPanel.SetActive(true);
StartPanel.SetActive(false);
MakeRoomPanel.SetActive(false);
for (int i = 0; i < PlayerBtnarr.Length; i++)
{
PlayerName[i] = " ";
}
if (PhotonNetwork.IsMasterClient)//마스터 클라이언트인 경우 스스로 자기 위치를 배정
{
PlayerName[0] = PhotonNetwork.LocalPlayer.NickName;
PlayerBtn[0].transform.GetChild(0).GetComponent<Image>().gameObject.SetActive(true);
PlayerBtn[0].transform.GetChild(1).GetComponent<Text>().text = PhotonNetwork.LocalPlayer.NickName;
PlayerBtn[0].transform.GetChild(2).GetComponent<Image>().sprite = Master;
PlayerReadyarr[0] = 2;
ReadyBtn.image.sprite = StartImage;
selfnum = 0;
}
print("방참가완료");
}
방장은 시작BTN을 가지고 있고 그 이외에 플레이어는 준비BTN을 가지고 있다.
public override void OnPlayerEnteredRoom(Player newPlayer)
{
//RoomRenewal();
ChatRPC("<color=yellow>" + newPlayer.NickName + "님이 참가하셨습니다</color>", newPlayer.NickName);
if(PhotonNetwork.IsMasterClient)//마스터 클라이언트만 새로운 클라이언트한테 방 정보에 대한 데이터를 전송한다.
{
photonView.RPC("UpdateGameState", newPlayer, PlayerBtnarr, PlayerName, PlayerReadyarr);
}
}
다른 플레이어가 들어오면 마스터 클라이언트가 방 정보를 전송
[PunRPC]
void UpdateGameState(int []newPlayerBtnarr, string[] newPlayerName, int[] newPlayerReadyarr)
{
PlayerBtnarr = newPlayerBtnarr;
PlayerName = newPlayerName;
PlayerReadyarr = newPlayerReadyarr;
for (int i=0; i< PlayerBtnarr.Length; i++)
{
if (PlayerBtnarr[i] == 0)
{
PlayerBtn[i].image.sprite = O;
if (PlayerName[i] != " ")//만약 열려있고 사람이 차있다면 이미지와 닉네임 표시
{
PlayerBtn[i].transform.GetChild(0).GetComponent<Image>().gameObject.SetActive(true);
PlayerBtn[i].transform.GetChild(1).GetComponent<Text>().text = PlayerName[i];
}
if (PlayerReadyarr[i] ==1)
{
PlayerBtn[i].transform.GetChild(2).GetComponent<Image>().sprite = ReadyO;
}
else if(PlayerReadyarr[i] == 2)
{
PlayerBtn[i].transform.GetChild(2).GetComponent<Image>().sprite = Master;
}
}
else
{
PlayerBtn[i].image.sprite = X;
PlayerBtn[i].transform.GetChild(0).GetComponent<Image>().gameObject.SetActive(false);
PlayerBtn[i].transform.GetChild(1).GetComponent<Text>().text = " ";
PlayerBtn[i].transform.GetChild(2).GetComponent<Image>().sprite = ReadyX;
}
}
for (int i = 0; i < PlayerBtnarr.Length; i++)
{
if (PlayerBtnarr[i] == 0 && PlayerName[i] == " ")//들어갈 수 있는 공간을 찾아라
{
selfnum = i;
PV.RPC("characterIamge", RpcTarget.All, i,1, PhotonNetwork.NickName);
break;
}
}
}
들어갈 슬롯이 있다면??
[PunRPC]
void characterIamge(int num, int vaild, string Nickname)
{
PlayerName[num] = Nickname;
if (vaild==1)//들어왔다면??
{
PlayerBtn[num].transform.GetChild(0).GetComponent<Image>().gameObject.SetActive(true);
PlayerBtn[num].transform.GetChild(1).GetComponent<Text>().text = PlayerName[num];
}
else//나갔다면??
{
PlayerBtn[num].transform.GetChild(0).GetComponent<Image>().gameObject.SetActive(false);
PlayerBtn[num].transform.GetChild(1).GetComponent<Text>().text = " ";
PlayerBtn[num].transform.GetChild(2).GetComponent<Image>().sprite = ReadyX;
PlayerName[num] = " ";
PlayerReadyarr[num] = 0;
}
}
Ready 버튼을 누르면 RPC를 통해 다른 플레이어들한테 준비 버튼을 눌렀다는 사실을 알려준다.
public void CharactorSlotClick(int num)
{
if(PhotonNetwork.IsMasterClient)
{
PV.RPC("ChangeCharactorSlot", RpcTarget.All,num);//빈칸 번호를 넘김
}
}
public void ChangeCharactorSlot(int num)
{
if (PlayerBtn[num].image.sprite == O && PlayerName[num]==" ")//만약 열려있고 사람이 안들어와 있다면 닫는거 가능
{
PlayerBtnarr[num] = 1;
PlayerBtn[num].image.sprite = X;
}
else if(PlayerBtn[num].image.sprite == X && PlayerName[num] == " ")
{
PlayerBtnarr[num] = 0;
PlayerBtn[num].image.sprite = O;
}
}
방장이 방을 떠나면 남아있던 플레이어가 방장 권한을 얻게 된다.
public void LeaveRoom()
{
PV.RPC("characterIamge", RpcTarget.All, selfnum, 0, " ");//나가면서 자기정보를 지우고 나감
PhotonNetwork.LeaveRoom();
}
public override void OnLeftRoom()
{
for(int i=0; i<PlayerBtnarr.Length;i++)//방을 떠나면서 방 정보 초기화
{
ChatText[i].text = " ";
PlayerBtn[i].image.sprite = O;
ReadyBtn.image.sprite = ReadyImage;
PlayerBtnarr[i] = 0;
PlayerName[i] = " ";
PlayerReadyarr[i] = 0;
}
PhotonNetwork.JoinLobby();
RoomPanel.SetActive(false);
StartPanel.SetActive(true);
}
public override void OnMasterClientSwitched(Player newMasterClient)
{
if (PhotonNetwork.IsMasterClient)
{
HandleNewMasterClient();
}
void HandleNewMasterClient()
{
ReadyBtn.image.sprite = StartImage;
PV.RPC("MasterSwitch", RpcTarget.All, selfnum);
}
}
[PunRPC]
void MasterSwitch(int num)
{
PlayerReadyarr[num] = 2;
PlayerBtn[num].transform.GetChild(2).GetComponent<Image>().sprite = Master;
}
지금 위 과정에서 플레이어가 동시에 들어오면
for (int i = 0; i < PlayerBtnarr.Length; i++)
{
if (PlayerBtnarr[i] == 0 && PlayerName[i] == " ")//들어갈 수 있는 공간을 찾아라
{
selfnum = i;
PV.RPC("characterIamge", RpcTarget.All, i,1, PhotonNetwork.NickName);
break;
}
}
이 부분에 대해 경쟁조건이 발생할 수도 있겠다는 생각이 들었다. 추후에 수정을 하던지 아니면 Lock을 사용해서 동기화 문제를 해결하도록 하겠다.(실제로 동시에 방에 들어가니 문제가 발생...)
'UNITY > 크레이지아케이드 모작' 카테고리의 다른 글
TileMap (0) | 2024.07.19 |
---|---|
캐릭터 움직임 구현 (0) | 2024.07.18 |
방 만들기 / 채팅 구현 (0) | 2024.07.13 |
오류 모음 (0) | 2024.07.12 |
크아 모작 기본적인 버튼 구현 (0) | 2024.06.28 |