UNITY/크레이지아케이드 모작

방 구현(Ready)

2zreal 2024. 7. 16. 22:30

오늘은 슬롯의 캐릭터 이미지와 준비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