PUN丨(四)大厅建房解析
时间:2020-05-30
本文章向大家介绍PUN丨(四)大厅建房解析,主要包括PUN丨(四)大厅建房解析使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
大家好,我是SKODE。
小提示:选中左侧目录,可快速找到所需内容
本系列博客地址:传送门
一、实现目标
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 Parameters
Dictionary<string, RoomInfo> cachedRoomList = new Dictionary<string, RoomInfo>();
Dictionary<string, GameObject> roomListEntries = new Dictionary<string, GameObject>();
Dictionary<int, GameObject> playerListEntries;
#endregion
#region Mono CallBacks
public void Awake()
{
PhotonNetwork.AutomaticallySyncScene = true;
PlayerNameInput.text = "Player " + Random.Range(1000, 10000);
}
#endregion
#region PUN CallBacks
public 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)
{