privatevoidAwake() { // Disable connected objects until connected to Photon server foreach (var obj in waitingConnectedObjects) obj.SetActive(false); }
privatevoidUpdate() { if (Input.GetKeyDown(KeyCode.Escape)) SceneManager.LoadScene("Menu");
publicclassJoinRoom : MonoBehaviour { public GameObject roomEntryPrefab; public Transform roomListContent; public TMP_InputField roomNameInputField; privatereadonly Dictionary<string, GameObject> _roomEntries = new();
privatevoidUpdate() { if (Input.GetKeyDown(KeyCode.Escape)) PhotonNetwork.LoadLevel("Lobby");
if (!NetworkManager.Instance().IsRoomListUpdated() && _roomEntries.Count > 0) return;
// Delete old entries foreach (var entry in _roomEntries.Values) Destroy(entry); _roomEntries.Clear();
foreach (var roomInfo in NetworkManager.Instance().RoomList()) { if (roomInfo.RemovedFromList) continue;
// Only show open rooms with available slots if (!roomInfo.IsOpen || roomInfo.PlayerCount >= roomInfo.MaxPlayers) continue;
var entryObj = Instantiate(roomEntryPrefab, roomListContent); _roomEntries[roomInfo.Name] = entryObj;
// Set room info text var text = entryObj.GetComponentInChildren<TMP_Text>(); text.text = $"Room: {roomInfo.Name} " + $"Players: {roomInfo.PlayerCount}/{roomInfo.MaxPlayers}";
// Set button click listener var button = entryObj.GetComponent<Button>(); var capturedName = roomInfo.Name; button.onClick.AddListener(() => { roomNameInputField.text = capturedName; }); } }
publicvoidOnJoinButtonClicked() { if (string.IsNullOrEmpty(roomNameInputField.text)) return;
publicoverridevoidOnPlayerPropertiesUpdate(Photon.Realtime.Player player, Hashtable changedProps) { if (!changedProps.ContainsKey(PlayerReadyKey)) return;
if (PhotonNetwork.IsMasterClient) TryStartGame(); }
privatestaticvoidTryStartGame() { // check if all players are ready var readyPlayers = 0; foreach (var player in PhotonNetwork.PlayerList) { if (!player.CustomProperties.TryGetValue(PlayerReadyKey, outvar readyObj)) return; if (!(bool)readyObj) return;
readyPlayers++; }
if (readyPlayers == PhotonNetwork.CurrentRoom.MaxPlayers) PhotonNetwork.LoadLevel("Game"); } }
Game
Players will keep some status from the room, e.g., appearance(color).
Use Photon custom properties to sync player appearance.
privatevoidAwake() { _spriteRenderer = GetComponent<SpriteRenderer>(); if (photonView.Owner.CustomProperties.TryGetValue(PlayerColorKey, outvar colorObj)) { // Retrieve and apply the color from custom properties var rgb = (float[])colorObj; _spriteRenderer.color = new Color(rgb[0], rgb[1], rgb[2]); } else { // Default color if none is set _spriteRenderer.color = Color.white; } }
privatevoidUpdate() { if (!photonView.IsMine) return;
if (SceneManager.GetActiveScene().name == "Game") return; if (Input.GetKeyDown(KeyCode.Alpha1)) SetColor(Color.red); elseif (Input.GetKeyDown(KeyCode.Alpha2)) SetColor(Color.green); elseif (Input.GetKeyDown(KeyCode.Alpha3)) SetColor(Color.blue); elseif (Input.GetKeyDown(KeyCode.Alpha4)) SetColor(Color.yellow); }
privatevoidSetColor(Color color) { _spriteRenderer.color = color; var rgb = new[] { color.r, color.g, color.b }; var props = new Hashtable { { PlayerColorKey, rgb } }; PhotonNetwork.LocalPlayer.SetCustomProperties(props); }
publicoverridevoidOnPlayerPropertiesUpdate(Photon.Realtime.Player targetPlayer, Hashtable changedProps) { if (changedProps.ContainsKey(PlayerColorKey)) { if (photonView.Owner.Equals(targetPlayer)) { var rgb = (float[])changedProps[PlayerColorKey]; _spriteRenderer.color = new Color(rgb[0], rgb[1], rgb[2]); } } } }
Menu
Destroy the NetworkManager instance when returning to the menu scene to avoid some bugs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
publicclassMenu : MonoBehaviour { privatevoidAwake() { if (NetworkManager.Instance()) Destroy(NetworkManager.Instance().gameObject); }
privatevoidUpdate() { if (Input.GetKeyDown(KeyCode.Escape)) Application.Quit(); }