Unity

[포톤] 직접 예제 만들어보기 (랜덤 입장할 때, 필터링하기 / 매칭하기)

푸쿠이 2021. 9. 29. 16:53
참고

https://doc.photonengine.com/ko-kr/pun/current/gameplay/synchronization-and-state

 

필터링하기

CustomPropertes를 사용하면 된다.

되게 간단하다.

 

1. CreateRoom(설정 값 A)

방을 생성할 때, 필터링하고 싶은 설정 값을 RoomOption 변수의 CustomProperties에 대입한다.

// UI에서 값 얻어오기.
byte maxPlayers = byte.Parse(m_dropdown_RoomMaxPlayers.options[m_dropdown_RoomMaxPlayers.value].text); // 드롭다운에서 값 얻어오기.
byte maxTime = byte.Parse(m_dropdown_MaxTime.options[m_dropdown_MaxTime.value].text);

// 방 옵션 설정하기.
RoomOptions roomOptions = new RoomOptions();
roomOptions.MaxPlayers = maxPlayers; // 인원 지정.
roomOptions.CustomRoomProperties = new ExitGames.Client.Photon.Hashtable() { { "maxTime", maxTime } }; // 게임 시간 지정.
roomOptions.CustomRoomPropertiesForLobby = new string[] { "maxTime" }; // 여기에 키 값을 등록해야, 참가할 때 필터링이 가능하다.

// 방 생성할 때, 옵션 넣어주기.
PhotonNetwork.CreateRoom(null, roomOptions);

2. JoinRandomRoom(설정 값 A)

설정했던 CustomProperties 값을 토대로 필터링해서 입장한다.

// UI에서 값 얻어오기.
byte maxPlayers = byte.Parse(m_dropdown_RoomMaxPlayers.options[m_dropdown_RoomMaxPlayers.value].text); // 드롭다운에서 값 얻어오기.
byte maxTime = byte.Parse(m_dropdown_MaxTime.options[m_dropdown_MaxTime.value].text);

// 방 옵션 설정한 것 그대로 HashTable 만들어준다. 이걸로 필터링하는 것이다.
ExitGames.Client.Photon.Hashtable customProperties = new ExitGames.Client.Photon.Hashtable() { { "maxTime", maxTime } };

// 방 입장할 때, 필터링할 옵션 넣어주기.
// maxPlayers는 자주 쓰이니까, 따로 변수로 빼준 듯하다.
PhotonNetwork.JoinRandomRoom(customProperties, maxPlayers);

 

나는 매칭 시스템을 할 것이라서 생성과 입장을 따로 두지 않았다.

방이 없으면 만들고, 방이 있으면 참가하도록 했다.

// UI에서 값 얻어오기.
byte maxPlayers = byte.Parse(m_dropdown_RoomMaxPlayers.options[m_dropdown_RoomMaxPlayers.value].text); // 드롭다운에서 값 얻어오기.
byte maxTime = byte.Parse(m_dropdown_MaxTime.options[m_dropdown_MaxTime.value].text);

// 방 옵션 설정하기.
RoomOptions roomOptions = new RoomOptions();
roomOptions.MaxPlayers = maxPlayers; // 인원 지정.
roomOptions.CustomRoomProperties = new ExitGames.Client.Photon.Hashtable() { { "maxTime", maxTime } }; // 게임 시간 지정.
roomOptions.CustomRoomPropertiesForLobby = new string[] { "maxTime" }; // 여기에 키 값을 등록해야, 참가할 때 필터링이 가능하다.

// 방 참가를 시도하고, 실패하면 생성해서 참가함.
PhotonNetwork.JoinRandomOrCreateRoom(
expectedCustomRoomProperties: new ExitGames.Client.Photon.Hashtable() { { "maxTime", maxTime } }, expectedMaxPlayers: maxPlayers, // 참가할 때의 기준.
roomOptions: roomOptions // 생성할 때의 기준.
);

 

매칭 시스템

전체적인 흐름은

 

1. 매칭 버튼을 누른다. (예를 들어서 최대 플레이어 수를 3으로 했다치자.)

-> 방이 없으면 만든다.

-> 방이 있으면 참가한다.

 

2. 방에 참가해서 기다린다.

-> 플레이어 수가 채워지지 않았다면, 로딩 UI 보여주면서 기다린다.

-> 플레이어 수가 채워졌다면, 방에 입장한 사람 모두가 씬을 이동한다.

 

움짤로 보는 게 편할 것 같다.

같은 설정 값일 땐, 서로 매칭이 된다.

다른 설정 값이면, 아예 방이 달라져서 만나지 않는다.

매칭 취소하면, 이렇게.

 

잘 동작하는 것 같다!!

전체 코드는 이렇다.

using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using Photon.Realtime;

public class MyLauncher : MonoBehaviourPunCallbacks
{
    public InputField m_inputField_Nickname; // 닉네임 입력받는 곳.
    public Dropdown m_dropdown_RoomMaxPlayers; // 최대 인원 몇 명까지 할지.
    public Dropdown m_dropdown_MaxTime; // 게임 시간은 몇 초로 정할 건지.

    public GameObject m_panel_Loading; // 로딩 UI.
    public Text m_text_CurrentPlayerCount; // 로딩 UI 중에서 현재 인원 수를 나타냄.

    void Awake()
    {
        // 마스터 클라이언트는 PhotonNetwork.LoadLevel()를 호출할 수 있고, 모든 연결된 플레이어는 자동적으로 동일한 레벨을 로드한다.
        PhotonNetwork.AutomaticallySyncScene = true;

        m_panel_Loading.SetActive(false);
    }

    void Start()
    {
        print("서버 연결 시도.");
        PhotonNetwork.ConnectUsingSettings();
    }

    public void JoinRandomOrCreateRoom()
    {
        string nick = m_inputField_Nickname.text;

        print($"{nick} 랜덤 매칭 시작.");
        PhotonNetwork.LocalPlayer.NickName = nick; // 현재 플레이어 닉네임 설정하기.

        // UI에서 값 얻어오기.
        byte maxPlayers = byte.Parse(m_dropdown_RoomMaxPlayers.options[m_dropdown_RoomMaxPlayers.value].text); // 드롭다운에서 값 얻어오기.
        int maxTime = int.Parse(m_dropdown_MaxTime.options[m_dropdown_MaxTime.value].text);

        RoomOptions roomOptions = new RoomOptions();
        roomOptions.MaxPlayers = maxPlayers; // 인원 지정.
        roomOptions.CustomRoomProperties = new ExitGames.Client.Photon.Hashtable() { { "maxTime", maxTime } }; // 게임 시간 지정.
        roomOptions.CustomRoomPropertiesForLobby = new string[] { "maxTime" }; // 여기에 키 값을 등록해야, 필터링이 가능하다.

        // 방 참가를 시도하고, 실패하면 생성해서 참가함.
        PhotonNetwork.JoinRandomOrCreateRoom(
            expectedCustomRoomProperties: new ExitGames.Client.Photon.Hashtable() { { "maxTime", maxTime } }, expectedMaxPlayers: maxPlayers, // 참가할 때의 기준.
            roomOptions: roomOptions // 생성할 때의 기준.
        );
    }

    public void CancelMatching()
    {
        print("매칭 취소.");
        m_panel_Loading.SetActive(false);

        print("방 떠남.");
        PhotonNetwork.LeaveRoom();
    }

    private void UpdatePlayerCounts()
    {
        m_text_CurrentPlayerCount.text = $"{PhotonNetwork.CurrentRoom.PlayerCount} / {PhotonNetwork.CurrentRoom.MaxPlayers}";
    }

    #region 포톤 콜백 함수

    public override void OnConnectedToMaster()
    {
        print("서버 접속 완료.");

    }
    public override void OnJoinedRoom()
    {
        print("방 참가 완료.");

        Debug.Log($"{PhotonNetwork.LocalPlayer.NickName}은 인원수 {PhotonNetwork.CurrentRoom.MaxPlayers} 매칭 기다리는 중.");
        UpdatePlayerCounts();

        m_panel_Loading.SetActive(true);
    }

    public override void OnPlayerEnteredRoom(Player newPlayer)
    {
        Debug.Log($"플레이어 {newPlayer.NickName} 방 참가.");
        UpdatePlayerCounts();

        if (PhotonNetwork.IsMasterClient)
        {
            // 목표 인원 수 채웠으면, 맵 이동을 한다. 권한은 마스터 클라이언트만.
            // PhotonNetwork.AutomaticallySyncScene = true; 를 해줬어야 방에 접속한 인원이 모두 이동함.
            if (PhotonNetwork.CurrentRoom.PlayerCount == PhotonNetwork.CurrentRoom.MaxPlayers)
            {
                PhotonNetwork.LoadLevel("Game");
            }
        }
    }

    public override void OnPlayerLeftRoom(Player otherPlayer)
    {
        Debug.Log($"플레이어 {otherPlayer.NickName} 방 나감.");
        UpdatePlayerCounts();
    }

    #endregion
}