PUN☀️四、服务器大厅建房解析
生活随笔
收集整理的這篇文章主要介紹了
PUN☀️四、服务器大厅建房解析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 🟥 實現目標
- 🟧 大廳思路
- 🟨 主要腳本
- LobbyMainPanel
- PlayerListEntry
🟥 實現目標
Demo:DemoAsteroids大廳的解析
🟧 大廳思路
Awake:設置同步場景的方式登陸按鈕:同步本地昵稱、連接到服務器連接到服務器回調:關閉登陸界面,打開 創建房間 / 加入房間 / 顯示房間列表 的面板選擇界面選擇創建房間界面的Btn:打開創建房間界面創建房間界面:輸入房間名、最大人數、擁有創建房間、返回的按鈕返回按鈕:返回到功能選擇界面創建房間Btn:根據房間名、最大人數,創建服務器房間創建/加入房間回調:打開房間內面板、實例化當前所有玩家的條形信息預制體,并將(昵稱、是否準備)信息初始化到該預制體上的腳本上↓條形信息物體:上有腳本:保存了該玩家的 ID、昵稱、準備信息根據初始化的ID==本地玩家ID?不等于則不顯示該預制體的準備按鈕(即咱們不顯示別人電腦的ready,咱們只能控制咱們的ready)若等于,即代表著這個預制體是我們自己的。則顯示準備按鈕。且將準備信息等做為自定義的同步信息根據本房間內,該玩家的Number,決定這個預制體是什么顏色。(demo設定最多8人,因此這有8種對應的case)【用PUN的 Number更新回調實現】注意,這兒要用到PUN自帶的腳本:PlayerNumbering,要將其掛在場景中上有準備按鈕:每次點擊,改變自身狀態(是否關閉等)、同步自身是否準備信息若自己是主服務器,則還可根據當前玩家是否都已準備,顯示開始游戲按鈕(檢查是否都已準備,就是foreach所有玩家的準備信息,進行判斷)開始游戲按鈕:設置當前房間狀態:不可再加入、大廳列表不可見(隱身)PUN同步加載場景加入隨機房間按鈕:加入隨機房間,顯示服務器房間界面返回按鈕:退出服務器房間,返回到功能選擇界面顯示房間列表按鈕:使用加入大廳API,使PUN調用 刷新大廳列表 回調,在該回調中完成相關邏輯(該回調會傳入所有房間列表緩存):清空、刪掉房間預制體、根據從網絡獲得的緩存列表,判斷房間是否可加入、可見性、標記性,刪除不需要的房間,將需要的房間添加到本地房間列表。更新實例化本地房間列表開始游戲按鈕狀態:只有主客戶端進行檢測判斷。(其他客戶端沒有開游戲的資格,自然不用檢測)主客戶端點擊準備時、本地玩家進入房間時、(新玩家進來了,當然關閉按鈕了)其他玩家進入房間時、(新玩家進來了,當然關閉按鈕了)其他玩家離開房間時、主客戶端切換給別人時、玩家屬性更新時、(PUN回調)房間列表更新時機:顯示房間列表信息按鈕、本地玩家退出大廳回調、本地玩家離開房間回調、其他玩家加入房間回調、其他玩家離開房間回調、🟨 主要腳本
該場景主要由這兩個腳本實現功能
PlayerNumbering作為PUN實用腳本,掛載到場景中,配合我們寫的代碼。
LobbyMainPanel
using ExitGames.Client.Photon; using Photon.Realtime; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;namespace Photon.Pun.Demo.Asteroids {public class LobbyMainPanel : MonoBehaviourPunCallbacks{#region Public Parameters[Header("Login Panel")]public GameObject LoginPanel;[Tooltip("玩家昵稱輸入框")]public InputField PlayerNameInput;[Header("房間操作界面")]public GameObject SelectionPanel;[Header("Create Room Panel")]public GameObject CreateRoomPanel;public InputField RoomNameInputField;public InputField MaxPlayersInputField;[Header("Join Random Room Panel")]public GameObject JoinRandomRoomPanel;[Header("Room List Panel")]public GameObject RoomListPanel;public GameObject RoomListContent;public GameObject RoomListEntryPrefab;[Header("Inside Room Panel")]public GameObject InsideRoomPanel;public Button StartGameButton;public GameObject PlayerListEntryPrefab;#endregion#region Private ParametersDictionary<string, RoomInfo> cachedRoomList = new Dictionary<string, RoomInfo>();Dictionary<string, GameObject> roomListEntries = new Dictionary<string, GameObject>();Dictionary<int, GameObject> playerListEntries;#endregion#region Mono CallBackspublic void Awake(){PhotonNetwork.AutomaticallySyncScene = true;PlayerNameInput.text = "Player " + Random.Range(1000, 10000);}#endregion#region PUN CallBackspublic override void OnConnectedToMaster(){SetActivePanel(SelectionPanel.name);}//本地玩家進入房間時public override void OnJoinedRoom(){print("OnJoinedRoom");SetActivePanel(InsideRoomPanel.name);if (playerListEntries == null)playerListEntries = new Dictionary<int, GameObject>();foreach (Player p in PhotonNetwork.PlayerList){GameObject entry = Instantiate(PlayerListEntryPrefab);entry.transform.SetParent(InsideRoomPanel.transform);entry.transform.localScale = Vector3.one;entry.GetComponent<PlayerListEntry>().Initialize(p.ActorNumber, p.NickName);object isPlayerReady;if (p.CustomProperties.TryGetValue(AsteroidsGame.PLAYER_READY, out isPlayerReady)){entry.GetComponent<PlayerListEntry>().SetPlayerReady((bool)isPlayerReady);}playerListEntries.Add(p.ActorNumber, entry);}StartGameButton.gameObject.SetActive(CheckPlayersReady());Hashtable props = new Hashtable{{AsteroidsGame.PLAYER_LOADED_LEVEL, false}};PhotonNetwork.LocalPlayer.SetCustomProperties(props);}//刷新列表回調public override void OnRoomListUpdate(List<RoomInfo> roomList){ClearRoomListView();UpdateCachedRoomList(roomList);UpdateRoomListView();}public override void OnLeftLobby(){cachedRoomList.Clear();ClearRoomListView();}public override void OnCreateRoomFailed(short returnCode, string message){SetActivePanel(SelectionPanel.name);}public override void OnJoinRoomFailed(short returnCode, string message){SetActivePanel(SelectionPanel.name);}public override void OnJoinRandomFailed(short returnCode, string message){string roomName = "Room " + Random.Range(1000, 10000);RoomOptions options = new RoomOptions { MaxPlayers = 8 };PhotonNetwork.CreateRoom(roomName, options, null);}public override void OnLeftRoom(){SetActivePanel(SelectionPanel.name);foreach (GameObject entry in playerListEntries.Values){Destroy(entry.gameObject);}playerListEntries.Clear();playerListEntries = null;}//其他玩家進入房間時public override void OnPlayerEnteredRoom(Player newPlayer){GameObject entry = Instantiate(PlayerListEntryPrefab);entry.transform.SetParent(InsideRoomPanel.transform);entry.transform.localScale = Vector3.one;entry.GetComponent<PlayerListEntry>().Initialize(newPlayer.ActorNumber, newPlayer.NickName);playerListEntries.Add(newPlayer.ActorNumber, entry);StartGameButton.gameObject.SetActive(CheckPlayersReady());}public override void OnPlayerLeftRoom(Player otherPlayer){Destroy(playerListEntries[otherPlayer.ActorNumber].gameObject);playerListEntries.Remove(otherPlayer.ActorNumber);StartGameButton.gameObject.SetActive(CheckPlayersReady());}public override void OnMasterClientSwitched(Player newMasterClient){if (PhotonNetwork.LocalPlayer.ActorNumber == newMasterClient.ActorNumber){StartGameButton.gameObject.SetActive(CheckPlayersReady());}}public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps){if (playerListEntries == null)playerListEntries = new Dictionary<int, GameObject>();GameObject entry;if (playerListEntries.TryGetValue(targetPlayer.ActorNumber, out entry)){object isPlayerReady;if (changedProps.TryGetValue(AsteroidsGame.PLAYER_READY, out isPlayerReady)){entry.GetComponent<PlayerListEntry>().SetPlayerReady((bool)isPlayerReady);}}StartGameButton.gameObject.SetActive(CheckPlayersReady());}#endregion#region Public Methods//綁定到登陸按鈕public void OnLoginButtonClicked(){string playerName = PlayerNameInput.text;if (!playerName.Equals("")){PhotonNetwork.LocalPlayer.NickName = playerName;PhotonNetwork.ConnectUsingSettings();}else{Debug.LogError("Player Name is invalid.");}}//綁定到創建服務器房間按鈕public void OnCreateRoomButtonClicked(){string roomName = RoomNameInputField.text;roomName = (roomName.Equals(string.Empty)) ? "Room " + Random.Range(1000, 10000) : roomName;byte maxPlayers;byte.TryParse(MaxPlayersInputField.text, out maxPlayers);maxPlayers = (byte)Mathf.Clamp(maxPlayers, 2, 8);RoomOptions options = new RoomOptions { MaxPlayers = maxPlayers };PhotonNetwork.CreateRoom(roomName, options, null);}//給玩家信息條的準備按鈕使用。當本地玩家是主客戶端時,執行。public void LocalPlayerPropertiesUpdated(){StartGameButton.gameObject.SetActive(CheckPlayersReady());}//綁定到開始游戲按鈕public void OnStartGameButtonClicked(){//當前房間不可再加入PhotonNetwork.CurrentRoom.IsOpen = false;//讓當前房間不可見:在大廳的列表中搜不到。(并且當你創建這個房間時,也可設為隱身的房間)PhotonNetwork.CurrentRoom.IsVisible = false;PhotonNetwork.LoadLevel("DemoAsteroids-GameScene");}//綁定到加入隨機房間按鈕public void OnJoinRandomRoomButtonClicked(){SetActivePanel(JoinRandomRoomPanel.name);PhotonNetwork.JoinRandomRoom();}//綁定到顯示列表按鈕public void OnRoomListButtonClicked(){if (!PhotonNetwork.InLobby){//使用該API,使PUN調用 刷新大廳房間列表 回調,并在該回調完成相關邏輯。PhotonNetwork.JoinLobby();}SetActivePanel(RoomListPanel.name);}//綁定到創建房間界面的返回按鈕public void OnBackButtonClicked(){//這并不會執行,因為沒加入大廳if (PhotonNetwork.InLobby){PhotonNetwork.LeaveLobby();}SetActivePanel(SelectionPanel.name);}//綁定到加入隨機房間界面的返回按鈕上public void OnLeaveGameButtonClicked(){PhotonNetwork.LeaveRoom();}#endregion#region Private Methodsvoid SetActivePanel(string activePanel){LoginPanel.SetActive(activePanel.Equals(LoginPanel.name));SelectionPanel.SetActive(activePanel.Equals(SelectionPanel.name));CreateRoomPanel.SetActive(activePanel.Equals(CreateRoomPanel.name));JoinRandomRoomPanel.SetActive(activePanel.Equals(JoinRandomRoomPanel.name));RoomListPanel.SetActive(activePanel.Equals(RoomListPanel.name)); // UI should call OnRoomListButtonClicked() to activate thisInsideRoomPanel.SetActive(activePanel.Equals(InsideRoomPanel.name));}//檢查所有玩家是否已經準備bool CheckPlayersReady(){if (!PhotonNetwork.IsMasterClient){return false;}foreach (Player p in PhotonNetwork.PlayerList){object isPlayerReady;if (p.CustomProperties.TryGetValue(AsteroidsGame.PLAYER_READY, out isPlayerReady)){if (!(bool)isPlayerReady){return false;}}else{return false;}}return true;}//清空本地房間數據列表、刪除房間預制體void ClearRoomListView(){foreach (GameObject entry in roomListEntries.Values){Destroy(entry.gameObject);}roomListEntries.Clear();}//更新本地房間數據列表void UpdateCachedRoomList(List<RoomInfo> roomList){foreach (RoomInfo info in roomList){// 如果緩存房間中該房間為關閉狀態、不可見或被標記為已刪除,則從緩存房間列表中刪除該房間if (!info.IsOpen || !info.IsVisible || info.RemovedFromList){if (cachedRoomList.ContainsKey(info.Name)){cachedRoomList.Remove(info.Name);}continue;}// Update cached room infoif (cachedRoomList.ContainsKey(info.Name)){cachedRoomList[info.Name] = info;}// Add new room info to cacheelse{cachedRoomList.Add(info.Name, info);}}}//實例化房間預制體void UpdateRoomListView(){foreach (RoomInfo info in cachedRoomList.Values){GameObject entry = Instantiate(RoomListEntryPrefab);entry.transform.SetParent(RoomListContent.transform);entry.transform.localScale = Vector3.one;entry.GetComponent<RoomListEntry>().Initialize(info.Name, (byte)info.PlayerCount, info.MaxPlayers);roomListEntries.Add(info.Name, entry);}}#endregion} }PlayerListEntry
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="PlayerListEntry.cs" company="Exit Games GmbH"> // Part of: Asteroid Demo, // </copyright> // <summary> // Player List Entry // </summary> // <author>developer@exitgames.com</author> // --------------------------------------------------------------------------------------------------------------------using UnityEngine; using UnityEngine.UI;using ExitGames.Client.Photon; using Photon.Realtime; using Photon.Pun.UtilityScripts;namespace Photon.Pun.Demo.Asteroids {public class PlayerListEntry : MonoBehaviour{[Tooltip("玩家昵稱")]public Text PlayerNameText;public Image PlayerColorImage;public Button PlayerReadyButton;public Image PlayerReadyImage;int ownerId;bool isPlayerReady;#region Mono CallBackspublic void OnEnable(){//每次房間索引更新時調用PlayerNumbering.OnPlayerNumberingChanged += OnPlayerNumberingChanged;}public void Start(){if (PhotonNetwork.LocalPlayer.ActorNumber != ownerId){PlayerReadyButton.gameObject.SetActive(false);}else{Hashtable initialProps = new Hashtable() {{AsteroidsGame.PLAYER_READY, isPlayerReady}, {AsteroidsGame.PLAYER_LIVES, AsteroidsGame.PLAYER_MAX_LIVES}};PhotonNetwork.LocalPlayer.SetCustomProperties(initialProps);//這將在本地設置分數,并將同步它在游戲中盡快。PhotonNetwork.LocalPlayer.SetScore(0);PlayerReadyButton.onClick.AddListener(() =>{isPlayerReady = !isPlayerReady;SetPlayerReady(isPlayerReady);Hashtable props = new Hashtable() {{AsteroidsGame.PLAYER_READY, isPlayerReady}};PhotonNetwork.LocalPlayer.SetCustomProperties(props);//檢測是否全員準備,是則顯示開始游戲按鈕if (PhotonNetwork.IsMasterClient){FindObjectOfType<LobbyMainPanel>().LocalPlayerPropertiesUpdated();}});}}public void OnDisable(){PlayerNumbering.OnPlayerNumberingChanged -= OnPlayerNumberingChanged;}#endregionpublic void Initialize(int playerId, string playerName){ownerId = playerId;PlayerNameText.text = playerName;}private void OnPlayerNumberingChanged(){foreach (Player p in PhotonNetwork.PlayerList){if (p.ActorNumber == ownerId){PlayerColorImage.color = AsteroidsGame.GetColor(p.GetPlayerNumber());}}}public void SetPlayerReady(bool playerReady){PlayerReadyButton.GetComponentInChildren<Text>().text = playerReady ? "Ready!" : "Ready?";PlayerReadyImage.enabled = playerReady;}} }
大家還有什么問題,歡迎在下方留言!
如果你有 技術的問題 或 項目開發
都可以加下方聯系方式
和我聊一聊你的故事🧡
總結
以上是生活随笔為你收集整理的PUN☀️四、服务器大厅建房解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编译器的大小端模式
- 下一篇: C++ —— C++引用