-
Photon을 활용한 Matching 시스템 구축게임 클라이언트 개발/Photon 2024. 1. 16. 01:52
어몽어스와 같은 마피아 게임을 제작했던 Interactopia 프로젝트에서 Photon API를 활용하여 Matching 시스템을 구축했었다. 해당 프로젝트를 진행하면서 매칭 시스템에서 필요한 기능은 크게 방 만들기, 공개 방 참여하기, 비공개 방 참여하기, 총 세 가지라고 생각했다. 이번 글에선 각각의 기능을 어떻게 구현했는지에 대해 작성하고자 한다.
방 만들기
Photon에선 방을 만들때 방의 이름은 중복될 수 없으며, 비공개 방 참여를 위한 6자리 코드가 필요했다. 그래서 6자리 방 코드를 Photon API를 위한 방 이름으로 사용하고, 닉네임을 유저에게 보여질 방 이름으로 사용하기로 결정했다.
우선 중복되지 않는 방 코드를 생성하기 위해 Photon에서 제공되는 UserId와 현재 시간을 조합해 MD5 알고리즘을 활용하여 6자리의 문자열로 추출했다.
// Utilities.cs // Create a 6-digit room code public static string ComputeMD5(string seed, int length) { StringBuilder md5Str = new(); byte[] byteArr = Encoding.ASCII.GetBytes(seed); byte[] resultArr = (new MD5CryptoServiceProvider()).ComputeHash(byteArr); for (int idx = 0; idx < length; idx++) { md5Str.Append(resultArr[idx].ToString("X2")); } return md5Str.ToString(); }
대문자 알파벳 A부터 Z, 0부터 9까지 총 36개의 문자열이 6자리이므로 $36^6$개의 경우의 수가 존재하기 때문에 방의 이름이 중복될 가능성이 매우 낮다고 판단했다. 혹시라도 중복될 경우 다시 방 이름을 추출하도록 작성했다.
// CreateRoomPanel.cs // Implement a Photon event function to recreate the room if room creation fails. public override void OnCreateRoomFailed(short returnCode, string message) { createButton.interactable = true; switch (returnCode) { case ErrorCode.GameIdAlreadyExists: { CreateRoom(); break; } } }
방마다 마피아의 수나 투표 방식 등 설정은 방을 생성할 때 Custom Properties로 미리 초기화했으며, 공개 방 참여를 위해 필요한 방 이름(Photon으로 방에 접속하기 위한 실제 방 이름이 아닌 유저에게 보여질 방 이름)과 같이 로비에 공개할 Properties를 설정했다.
// CreateRoomPanel.cs private void CreateRoom() { // Set the properties of the room roomSetting = new ExitGames.Client.Photon.Hashtable(); roomSetting[CustomProperties.ROOM_NAME] = PhotonNetwork.LocalPlayer.NickName + "'s room"; // ... // Add the properties to get listed in the lobby roomSettingForLobby = new string[0]; roomSettingForLobby = ArrayHelper.Add(CustomProperties.ROOM_NAME, roomSettingForLobby); // ... // Set the room option string roomName = Utilities.ComputeMD5(PhotonNetwork.LocalPlayer.UserId + "_" + System.DateTime.UtcNow.ToFileTime().ToString(), 3); RoomOptions roomOption = new RoomOptions { MaxPlayers = maxPlayer, IsVisible = !privacyModeToggle.isOn, IsOpen = true, CustomRoomProperties = roomSetting, CustomRoomPropertiesForLobby = roomSettingForLobby, PublishUserId = true }; PhotonNetwork.CreateRoom(roomName, roomOption); }
공개 방 참여하기
공개 방 참여하기를 구현하기 위해선 필요한 Photon Callback 함수는 OnRoomListUpdate이다. 파라미터로 전달받는 roomList는 모든 방을 전달하지 않고 변경이 발생한(추가, 제거, 공개 여부 등) 방만 전달된다.
// GameManager.cs public override void OnRoomListUpdate(List<RoomInfo> roomList) { networkManager.UpdateRoomList(roomList); }
Interactopia에선 백앤드를 구축할 여력이 없었다. 6개월안에 기획, 개발 및 배포, 후속 관리까지 진행해야 하는데 팀원 셋 모두 클라이언트여서 새로 백앤드를 공부하여 구축하기엔 시간이 부족했고, 금전적인 지원 여부도 불명확했다. 그래서 게임에 생성된 모든 방을 클라이언트에서 관리하기로 결정했다.
// NetworkManager.cs private List<RoomInfo> roomList = new List<RoomInfo>(); // Event variables for updating the UI public Action<List<RoomInfo>> RoomListAdded = null; public Action<List<RoomInfo>> RoomListRemoved = null; public Action<List<RoomInfo>> RoomListUpdated = null; public void UpdateRoomList(List<RoomInfo> roomList) { var addedRoomList = new List<RoomInfo>(); var removedRoomList = new List<RoomInfo>(); var updatedRoomList = new List<RoomInfo>(); foreach (RoomInfo room in roomList) { // If the room has been removed if (room.RemovedFromList) { this.roomList.Remove(room); removedRoomList.Add(room); continue; } int idx = this.roomList.FindIndex(x => x.Name.Equals(room.Name)); if (idx >= 0) // If the room has been updated { this.roomList[idx] = room; updatedRoomList.Add(room); } else // If the room has been added { this.roomList.Add(room); addedRoomList.Add(room); } } // Invode the event variables RoomListAdded?.Invoke(addedRoomList); RoomListRemoved?.Invoke(removedRoomList); RoomListUpdated?.Invoke(updatedRoomList); }
공개 방 참여를 위한 UI를 통해 원하는 방을 선택한 후 참여 버튼을 통해 해당 방에 참여할 수 있도록 구현했다.
// PublicJoinPanel.cs // The event function called when the join button is pressed after selecting the desired room. public void OnClickJoinButton() { // Button click sound output and exception handling PhotonNetwork.JoinRoom(selectedRoomInfo.Name); }
비공개 방 참여하기
비공개 방 참여하기 기능을 구현하기 위해선 방을 비공개로 만드는 작업이 필요하다. 이를 위해 Photon에선 두 가지 변수를 제공한다. Room.IsVisible이 false일 경우, 방에는 참여할 수 있으나 OnRoomListUpdate Callback 함수에서 파라미터에 포함되지 않는 상태가 된다.
PhotonNetwork.CurrentRoom.IsVisible = false;
비공개 방 참여를 위한 UI에서 방 코드를 입력하면 해당 방에 참여할 수 있도록 구현했다.
// PrivateJoinPanel.cs // The event function called when the join button is pressed after entering the room code. public void OnClickEnterButton() { // Button click sound output and exception handling PhotonNetwork.JoinRoom(roomCodeInputField.text); }
'게임 클라이언트 개발 > Photon' 카테고리의 다른 글
Photon 동기화 방식 - Custom Properties (0) 2023.11.07 Photon 동기화 방식 - RPC Method (0) 2023.11.05 Photon 동기화 방식 - Photon View Component (0) 2023.11.03