로비에 입장하면 포톤 클라우드 서버는 현재 생성된 모든 룸 목록을 전달해준다. 로비에 접속하지 않고 포톤 클라우드 서버에만 접속한 경우에는 룸 목록을 받을 수 없다. PhtonManager 스크립트에 OnRoomListUpdate콜백 함수를 추가해 룸 목록을 전달 받는지를 확인해보자.

 

public  override void OnJoinedRoom() 
 //...중략
public override void OnRoomListUpdate(List<RoomInfo> roomList) {
    foreach (var roomInfo in roomList) {
        // 룸이 삭제된 경우
        Debug.Log($"Room={roomInfo.Name} ({roomInfo.PlayerCount}/{roomInfo.MaxPlayers})");
    }
}
//...중략

OnRoomListUpdate함수는 RoomInfo타입의 데이터를 리스트 자료형으로 넘겨준다. 다음 그림은 새로 빌드한 실행 파일로 세개의 룸을 생성하고 3번째 유저는 ROOM_034 룸에 입장했다. 마지막으로 유니티를 실행해 로비까지만 입장한 상태에서 콘솔뷰를 살펴보자 룸의 목록이 표시되고 ROOM_034 룸의PlayerCount와MaxPlayer가 2/20으로 표시된 것을 알 수 있다.

 

룸목록은 룸정보의 변화가 발생할 때마다 콜백 함수가 호출된다. 다만 삭제된 룸에 대한 정보도 넘어온다.

룸의 삭제여부는 RemovedFromList속성으로 알수 있다. 따라서 룸목록을 Dictionary타입의 자료형으로 관리한다. 앞서 작성했던 OnRoomListUpdate함수를 다음과 같이 수정한다.

 

룸 목록은 룸 이름과 해당 룸을 ScrollView하위에 생성할 RoomItem프리팹을 쌍으로 저장해야 관리하기 편리하기 때문에 dictionary자료형을 사용한다. c#에서 Dictionary를 사용하기 위해서 System.Collections.Generic 네임스페이스를 선언한다.

using System.Collections.Generic;

클래스 선언부에 룸목록에 대한 데이터를 저장할 rooms를 선언한다.

private Dictionary<string, GameObject> rooms = new Dictionary<string, GameObject>();

RoomItem프리팹을 로드할 변수를 Awake()에서 할당한다.

// RoomItem 프리팹 로드
roomItemPrefab = Resources.Load<GameObject>("RoomItem");

룸 목록이 갱신되면 호출되는 OnRoomListUpdate함수의 로직을 간단히 설명하면

 public override void OnRoomListUpdate(List<RoomInfo> roomList) {
        // 삭제된 RoomItem 프리팹을 저장할 임시변수
        GameObject tempRoom = null;

        foreach (var roomInfo in roomList) {
            if (roomInfo.RemovedFromList == true) {  // 룸이 삭제된 경우
                // 딕셔너리에서 룸 이름으로 검색해 저장된 RoomItem 프리팹를 추출
                rooms.TryGetValue(roomInfo.Name, out tempRoom);     
                Destroy(tempRoom); // RoomItem 프리팹 삭제        
                rooms.Remove(roomInfo.Name); // 딕셔너리에서 해당 룸 이름의 데이터를 삭제
            } else // 룸 정보가 변경된 경우
              {
                // 룸 이름이 딕셔너리에 없는 경우 새로 추가
                if (rooms.ContainsKey(roomInfo.Name) == false) {
                    // RoomInfo 프리팹을 scrollContent 하위에 생성
                    GameObject roomPrefab = Instantiate(roomItemPrefab, scrollContent);
                    // 룸 정보를 표시하기 위해 RoomInfo 정보 전달
                    roomPrefab.GetComponent<RoomData>().RoomInfo = roomInfo;

                    // 딕셔너리 자료형에 데이터 추가
                    rooms.Add(roomInfo.Name, roomPrefab);
                } else // 룸 이름이 딕셔너리에 없는 경우에 룸 정보를 갱신
                  {
                    rooms.TryGetValue(roomInfo.Name, out tempRoom); 룸검색해 RoomItem을 tempRoom에 저장
                    tempRoom.GetComponent<RoomData>().RoomInfo = roomInfo;  //룸 정보 전달
                }
            }
            Debug.Log($"Room={roomInfo.Name} ({roomInfo.PlayerCount}/{roomInfo.MaxPlayers})");
        }
    }

버튼 이벤트 동적 연결

OnRoomListUpdate() 함수에서 룸에 대한 정보에 따라서  RoomItem프리팹을 동적으로 생성하거나 이미 만들어진 RoomItem 프리팹에 룸 정보를 저장하고 클릭했을 때 버튼 이벤트에서 룸에 접속하기 위해 새로운 스크립트를 생성하고 이름을 RoomData로 지정한다. 스크립트는 다음과 같이 작성하고 프로젝트 뷰의 Resource 폴더에 있는 RoomItem 프리팹에 추가한다.

using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using TMPro;

public class RoomData : MonoBehaviour {
    private RoomInfo _roomInfo;
    private TMP_Text roomInfoText;   // 하위에 있는 TMP_Text를 저장할 변수
    private PhotonManager photonManager; // PhotonManager 접근 변수

    // 프로퍼티 정의
    public RoomInfo RoomInfo {
        get {
            return _roomInfo;
        }
        set {
            _roomInfo = value;
            // 룸 정보 표시
            roomInfoText.text = $"{_roomInfo.Name} ({_roomInfo.PlayerCount}/{_roomInfo.MaxPlayers})";
            // 버튼 클릭 이벤트에 함수 연결
            GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => OnEnterRoom(_roomInfo.Name));
        }
    }

    void Awake() {
        roomInfoText = GetComponentInChildren<TMP_Text>();
        photonManager = GameObject.Find("PhotonManager").GetComponent<PhotonManager>();
    }

    void OnEnterRoom(string roomName) {
        // 유저명 설정
        photonManager.SetUserId();
        //룸의 속성 정의
        RoomOptions ro =  new RoomOptions();
        ro.MaxPlayers = 20;  //룸에 입장할 수 있는 최대 접속자수
        ro.IsOpen = true;  // 룸의 오픈 여부
        ro.IsVisible = true; //로비에서 룸 목록에 노출시킬지 여부
        // 룸 접속
        PhotonNetwork.JoinRoom(roomName);
    }
}

RoomData 스크립트는 OnRoomListUpdate에서 룸정보가 갱신될때 마다 접근해 roomInfo 데이터를 넘겨받아서 내부적으로 저장하고하위에 있는 텍스트 UI에 룸 이름과 접속자 정보를 표시한다. 또한 버튼을 클릭했을 때 룸에 접속하는 함수를 람다식으로 연결한다.

 

//룸정보 표시
roomInfoText.text = $"{_roomInfo.Name} ({_roomInfo.PlayerCount}/{_roomInfo.MaxPlayers})";
// 버튼 클릭 이벤트에 함수 연결
GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => OnEnterRoom(_roomInfo.Name));

예제 게임을 다시 빌드하고 룸을 생성하고 입장한 후 유니티 에디터에서 로비에 입장만 한 상태에서 룸 목록이 표시 되는지 확인해보자. 다음은 룸을 2개 생성하고 2명의 유저는 같은 방에 들어가고 한명의 유저는 혼자 룸에 입장한 시나리오일 때의 룸 목록이다. 룸목록에 표시된 버튼을 클릭하며 해당 룸으로 입장하는지 확인해보자
   

+ Recent posts