Mooc Hero 2 - MP (二) —— 脚本:游戏登录、大厅、房间面板

之前在SP版本中用过,但是要经过RPC函数重写的脚本先不放

1.登录面板

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using Photon;

public class LoginPanelController : PunBehaviour {

	public GameObject loginPanel;		//游戏登录面板
	public GameObject userMessage;		//玩家昵称信息
	public Button backButton;			//后退按钮
	public GameObject lobbyPanel;		//游戏大厅面板
	public GameObject roomPanel;		//游戏房间面板
	public Text username;				//玩家昵称文本
	public Text connectionState;		//网络连接状态

	//初始化,根据当前客户端连接状态,显示相应的游戏面板
	void Start () {
		//如果未连接Photon服务器
		if (!PhotonNetwork.connected) {
			SetLoginPanelActive ();								//启用游戏登录面板
			username.text = PlayerPrefs.GetString ("Username");	//在本地保存玩家昵称
		} 
		//如果已连接Photon服务器
		else
			SetLobbyPanelActive ();	//启用游戏大厅面板
		connectionState.text = "";	//初始化网络连接状态文本信息
	}

//条件编译指令,只在Unity编辑器中(UNITY_EDITOR)编译此段代码
//#if(UNITY_EDITOR)	
	void Update(){		
		//在游戏画面左下角显示当前的网络连接状态
		connectionState.text = PhotonNetwork.connectionStateDetailed.ToString ();
	}
//#endif

	//启用游戏登录面板
	public void SetLoginPanelActive(){
		loginPanel.SetActive (true);				//启用游戏登录面板
		userMessage.SetActive (false);				//禁用玩家昵称信息
		backButton.gameObject.SetActive (false);	//禁用后退按钮
		lobbyPanel.SetActive (false);				//禁用游戏大厅面板
		if(roomPanel!=null)
			roomPanel.SetActive (false);				//禁用游戏房间面板
	}
	//启用游戏大厅面板
	public void SetLobbyPanelActive(){				
		loginPanel.SetActive (false);				//禁用游戏登录面板
		userMessage.SetActive (true);				//启用玩家昵称信息
		backButton.gameObject.SetActive (true);		//启用后退按钮
		lobbyPanel.SetActive (true);				//启用游戏大厅面板
	}

	//"登录"按钮事件处理函数
	public void ClickLogInButton(){							
		SetLobbyPanelActive ();			//启用游戏大厅面板
		//客户端连接Photon服务器,游戏版本标识符为“1.0”
		if (!PhotonNetwork.connected)						
			PhotonNetwork.ConnectUsingSettings ("1.0");		
		//如果玩家未输入昵称,这里自动为其分配一个昵称
		if (username.text == "")							
			username.text = "游客" + Random.Range (1, 9999);
		PhotonNetwork.player.name = username.text;			//设置玩家昵称
		PlayerPrefs.SetString ("Username", username.text);	//将玩家昵称保存在本地
	}
	//"退出"按钮事件处理函数
	public void ClickExitGameButton(){
		Application.Quit ();			//退出游戏应用
	}

	/**覆写IPunCallback回调函数,当玩家进入游戏大厅时调用
	 * 显示玩家昵称
	 */
	public override void OnJoinedLobby(){
		userMessage.GetComponentInChildren<Text> ().text
		= "欢迎," + PhotonNetwork.player.name;
	}

	/**覆写IPunCallback回调函数,当客户端断开与Photon服务器的连接时调用
	 * 游戏画面返回游戏登录面板
	 */
	public override void OnConnectionFail(DisconnectCause cause){
		SetLoginPanelActive ();
	}
}

2.大厅面板

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using Photon;

public class LobbyPanelController : PunBehaviour {

	public GameObject loginPanel;			//游戏登录面板
	public GameObject lobbyPanel;			//游戏大厅面板
	public GameObject userMessage;			//玩家昵称信息
	public Button backButton;				//返回按钮
	public GameObject lobbyLoadingLabel;	//游戏大厅加载提示信息
	public GameObject roomLoadingLabel;		//游戏房间加载提示信息
	public GameObject roomMessagePanel;		//房间信息面板
	public Button randomJoinButton;			//"随机进入房间"按钮
	public GameObject previousButton;		//"上一页"按钮
	public GameObject nextButton;			//"下一页"按钮
	public Text pageMessage;				//房间页数文本控件
	public GameObject createRoomPanel;		//创建房间面板
	public GameObject roomPanel;			//游戏房间面板

	private RoomInfo[] roomInfo;			//游戏大厅房间列表信息
	private int currentPageNumber;			//当前房间页
	private int maxPageNumber;				//最大房间页
	private int roomPerPage = 4;			//每页显示房间个数
	private GameObject[] roomMessage;		//游戏房间信息

	//当游戏大厅面板启用时调用,初始化信息
	void OnEnable(){
		currentPageNumber = 1;				//初始化当前房间页
		maxPageNumber = 1;					//初始化最大房间页	
		lobbyLoadingLabel.SetActive (true);	//启用游戏大厅加载提示信息
		roomLoadingLabel.SetActive (false);	//禁用游戏房间加载提示信息
		if(createRoomPanel!=null)
			createRoomPanel.SetActive (false);	//禁用创建房间面板

		//获取房间信息面板
		RectTransform rectTransform = roomMessagePanel.GetComponent<RectTransform> ();
		roomPerPage = rectTransform.childCount;		//获取房间信息面板的条目数

		//初始化每条房间信息条目
		roomMessage = new GameObject[roomPerPage];	
		for (int i = 0; i < roomPerPage; i++) {
			roomMessage [i] = rectTransform.GetChild (i).gameObject;
			roomMessage [i].SetActive (false);			//禁用房间信息条目
		}

		backButton.onClick.RemoveAllListeners ();		//移除返回按钮绑定的所有监听事件
		backButton.onClick.AddListener (delegate() {	//为返回按钮绑定新的监听事件
			PhotonNetwork.Disconnect();					//断开客户端与Photon服务器的连接
			loginPanel.SetActive(true);					//启用游戏登录面板
			lobbyPanel.SetActive(false);				//禁用游戏大厅面板
			userMessage.SetActive (false);				//禁用玩家昵称信息
			backButton.gameObject.SetActive (false);	//禁用返回按钮
		});
		if(roomPanel!=null)
			roomPanel.SetActive (false);					//禁用游戏房间面板
	}

	/**覆写IPunCallback回调函数,当玩家进入游戏大厅时调用
	 * 禁用游戏大厅加载提示
	 */
	public override void OnJoinedLobby(){
		lobbyLoadingLabel.SetActive (false);
	}
	/**覆写IPunCallback回调函数,当玩家进入游戏房间时调用
	 * 禁用游戏大厅面板,启用游戏房间面板
	 */
	public override void OnJoinedRoom(){
		lobbyPanel.SetActive (false);
		roomPanel.SetActive (true);
	}

	/**覆写IPunCallback回调函数,当客户端连接到MasterServer时调用
	 * 加入默认游戏大厅
	 * 效果等同于勾选PhotonServerSettings中的Auto-join Lobby
	public override void OnConnectedToMaster ()
	{
		PhotonNetwork.JoinLobby ();
	}
	*/

	/**覆写IPunCallback回调函数,当房间列表更新时调用
	 * 更新游戏大厅中房间列表的显示
	 */
	public override void OnReceivedRoomListUpdate(){
		roomInfo = PhotonNetwork.GetRoomList ();					//获取游戏大厅中的房间列表
		maxPageNumber = (roomInfo.Length - 1) / roomPerPage + 1;	//计算房间总页数
		if (currentPageNumber > maxPageNumber)		//如果当前页大于房间总页数时
			currentPageNumber = maxPageNumber;		//将当前房间页设为房间总页数
		pageMessage.text = currentPageNumber.ToString () + "/" + maxPageNumber.ToString ();	//更新房间页数信息的显示
		ButtonControl ();		//翻页按钮控制
		ShowRoomMessage ();		//显示房间信息

		if (roomInfo.Length == 0) {
			randomJoinButton.interactable = false;	//如果房间数为0,禁用"随机进入房间"按钮的交互功能
		} else
			randomJoinButton.interactable = true;	//如果房间数不为0,启用"随机进入房间"按钮的交互功能
	}

	//显示房间信息
	void ShowRoomMessage(){
		int start, end, i, j;
		start = (currentPageNumber - 1) * roomPerPage;			//计算需要显示房间信息的起始序号
		if (currentPageNumber * roomPerPage < roomInfo.Length)	//计算需要显示房间信息的末尾序号
			end = currentPageNumber * roomPerPage;
		else
			end = roomInfo.Length;

		//依次显示每条房间信息
		for (i = start,j = 0; i < end; i++,j++) {
			RectTransform rectTransform = roomMessage [j].GetComponent<RectTransform> ();
			string roomName = roomInfo [i].name;	//获取房间名称
			rectTransform.GetChild (0).GetComponent<Text> ().text = (i + 1).ToString ();	//显示房间序号
			rectTransform.GetChild (1).GetComponent<Text> ().text = roomName;				//显示房间名称
			rectTransform.GetChild (2).GetComponent<Text> ().text 						
				= roomInfo [i].playerCount + "/" + roomInfo [i].maxPlayers;					//显示房间人数
			Button button = rectTransform.GetChild (3).GetComponent<Button> ();				//获取"进入房间"按钮组件
			//如果游戏房间人数已满,或者游戏房间的Open属性为false(房间内游戏已开始),表示房间无法加入,禁用"进入房间"按钮
			if (roomInfo [i].playerCount == roomInfo [i].maxPlayers || roomInfo [i].open == false)
				button.gameObject.SetActive (false);
			//如果房间可以加入,启用"进入房间"按钮,给按钮绑定新的监听事件,加入此房间
			else {
				button.gameObject.SetActive (true);
				button.onClick.RemoveAllListeners ();
				button.onClick.AddListener (delegate() {
					ClickJoinRoomButton (roomName);
				});
			}
			roomMessage [j].SetActive (true);	//启用房间信息条目
		}
		//禁用不显示的房间信息条目
		while (j < 4) {
			roomMessage [j++].SetActive (false);
		}
	}

	//翻页按钮控制函数
	void ButtonControl(){
		//如果当前页为1,禁用"上一页"按钮;否则,启用"上一页"按钮
		if (currentPageNumber == 1)
			previousButton.SetActive (false);
		else
			previousButton.SetActive (true);
		//如果当前页等于房间总页数,禁用"下一页"按钮;否则,启用"下一页"按钮
		if (currentPageNumber == maxPageNumber)
			nextButton.SetActive (false);
		else
			nextButton.SetActive (true);
	}

	//"创建房间"按钮事件处理函数,启用创建房间面板
	public void ClickCreateRoomButton(){
		createRoomPanel.SetActive (true);
	}
	//"随机进入房间"按钮事件处理函数,玩家随机加入大厅中的房间,启用游戏房间加载提示信息
	public void ClickRandomJoinButton(){
		PhotonNetwork.JoinRandomRoom ();
		roomLoadingLabel.SetActive (true);
	}
	//"上一页"按钮事件处理函数
	public void ClickPreviousButton(){
		currentPageNumber--;		//当前房间页减一
		pageMessage.text = currentPageNumber.ToString () + "/" + maxPageNumber.ToString ();	//更新房间页数显示
		ButtonControl ();			//当前房间页更新,调动翻页控制函数
		ShowRoomMessage ();			//当前房间页更新,重新显示房间信息
	}
	//"下一页"按钮事件处理函数
	public void ClickNextButton(){
		currentPageNumber++;		//当前房间页加一
		pageMessage.text = currentPageNumber.ToString () + "/" + maxPageNumber.ToString ();	//更新房间页数显示
		ButtonControl ();			//当前房间页更新,调动翻页控制函数
		ShowRoomMessage ();			//当前房间页更新,重新显示房间信息
	}
	//"进入房间"按钮事件处理函数
	public void ClickJoinRoomButton(string roomName){
		PhotonNetwork.JoinRoom(roomName);	//根据房间名加入游戏房间
		roomLoadingLabel.SetActive (true);	//启用房间加载提示信息
	}
}
3.创建房间
using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class CreateRoomController : MonoBehaviour {

	public GameObject createRoomPanel;		//创建房间面板
	public GameObject roomLoadingPanel;		//禁用游戏房间加载提示信息
	public Text roomName;					//房间名称文本
	public Text roomNameHint;				//房间名称提示文本
	public GameObject maxPlayerToggle;		//最大玩家个数开关组

	private byte[] maxPlayerNum = { 2, 4 };	//最大玩家个数

	//创建房间面板激活时调用
	void OnEnable(){
		roomNameHint.text = "";	//清空房间名称提示文本
	}

	//"确认创建"按钮事件处理函数
	public void ClickConfirmCreateRoomButton(){
		RoomOptions roomOptions=new RoomOptions();
		RectTransform toggleRectTransform = maxPlayerToggle.GetComponent<RectTransform> ();
		int childCount = toggleRectTransform.childCount;
		//根据最大玩家个数开关组的打开情况,确认房间最大玩家个数
		for (int i = 0; i < childCount; i++) {
			if (toggleRectTransform.GetChild (i).GetComponent<Toggle> ().isOn == true) {
				roomOptions.maxPlayers = maxPlayerNum [i];
				break;
			}
		}

		RoomInfo[] roomInfos = PhotonNetwork.GetRoomList();	//获取游戏大厅内所有游戏房间
		bool isRoomNameRepeat = false;
		//遍历游戏房间,检查新创建的房间名是否与已有房间重复
		foreach (RoomInfo info in roomInfos) {
			if (roomName.text == info.name) {
				isRoomNameRepeat = true;
				break;
			}
		}
		//如果房间名称重复,房间名称提示文本显示"房间名称重复!"
		if (isRoomNameRepeat) {
			roomNameHint.text = "房间名称重复!";
		}
		//否则,根据玩家设置的房间名、房间玩家人数创建房间
		else {
			PhotonNetwork.CreateRoom (roomName.text, roomOptions, TypedLobby.Default);	//在默认游戏大厅中创建游戏房间
			createRoomPanel.SetActive (false);	//禁用创建房间面板
			roomLoadingPanel.SetActive (true);	//启用游戏房间加载提示信息
		}
	}

	//"取消创建"按钮事件处理函数
	public void ClickCancelCreateRoomButton(){
		createRoomPanel.SetActive (false);		//禁用创建房间面板
		roomNameHint.text = "";					//清空房间名称提示文本
	}
}

4.房间面板

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using Photon;

public class RoomPanelController : PunBehaviour {

	public GameObject lobbyPanel;		//游戏大厅面板
	public GameObject roomPanel;		//游戏房间面板
	public Button backButton;			//返回按钮
	public Text roomName;				//房间名称文本
	public GameObject[] Team1;			//队伍1面板(显示队伍1信息)
	public GameObject[] Team2;			//队伍2面板(显示队伍2信息)
	public Button readyButton;			//准备/开始游戏按钮
	public Text promptMessage;			//提示信息

	PhotonView pView;
	int teamSize;
	Text[] texts;
	ExitGames.Client.Photon.Hashtable costomProperties;

	void OnEnable () {
		pView = GetComponent<PhotonView>();					//获取PhotonView组件
		if(!PhotonNetwork.connected)return;
		roomName.text = "房间:" + PhotonNetwork.room.name;	//显示房间名称
		promptMessage.text = "";							//提示信息

		backButton.onClick.RemoveAllListeners ();			//移除返回按钮绑定的所有监听事件
		backButton.onClick.AddListener (delegate() {		//为返回按钮绑定新的监听事件
			PhotonNetwork.LeaveRoom ();						//客户端离开游戏房间
			lobbyPanel.SetActive (true);					//激活游戏大厅面板
			roomPanel.SetActive (false);					//禁用游戏房间面板
		});

		teamSize = PhotonNetwork.room.maxPlayers / 2;		//计算每队人数
		DisableTeamPanel ();								//初始化队伍面板
		UpdateTeamPanel (false);							//更新队伍面板(false表示不显示本地玩家信息)

		//交替寻找两队空余位置,将玩家信息放置在对应空位置中
		for (int i = 0; i < teamSize; i++) {	
			if (!Team1 [i].activeSelf) {		//在队伍1找到空余位置
				Team1 [i].SetActive (true);		//激活对应的队伍信息UI
				texts = Team1 [i].GetComponentsInChildren<Text> ();
				texts [0].text = PhotonNetwork.playerName;				//显示玩家昵称
				if(PhotonNetwork.isMasterClient)texts[1].text="房主";	//如果玩家是MasterClient,玩家状态显示"房主"
				else texts [1].text = "未准备";							//如果玩家不是MasterClient,玩家状态显示"未准备"
				costomProperties = new ExitGames.Client.Photon.Hashtable () {	//初始化玩家自定义属性
					{ "Team","Team1" },		//玩家队伍
					{ "TeamNum",i },		//玩家队伍序号
					{ "isReady",false },	//玩家准备状态
					{ "Score",0 }			//玩家得分
				};
				PhotonNetwork.player.SetCustomProperties (costomProperties);	//将玩家自定义属性赋予玩家
				break;
			} else if (!Team2 [i].activeSelf) {	//在队伍2找到空余位置
				Team2 [i].SetActive (true);		//激活对应的队伍信息UI
				texts = Team2 [i].GetComponentsInChildren<Text> ();		//显示玩家昵称
				if(PhotonNetwork.isMasterClient)texts[1].text="房主";	//如果玩家是MasterClient,玩家状态显示"房主"
				else texts [1].text = "未准备";							//如果玩家不是MasterClient,玩家状态显示"未准备"
				costomProperties = new ExitGames.Client.Photon.Hashtable () {	//初始化玩家自定义属性
					{ "Team","Team2" },		//玩家队伍
					{ "TeamNum",i },		//玩家队伍序号
					{ "isReady",false },	//玩家准备状态
					{ "Score",0 }			//玩家得分
				};
				PhotonNetwork.player.SetCustomProperties (costomProperties);	//将玩家自定义属性赋予玩家
				break;
			}
		}
		ReadyButtonControl ();	//设置ReadyButton的按钮事件
	}

	/**覆写IPunCallback回调函数,当玩家属性更改时调用
	 * 更新队伍面板中显示的玩家信息
	 */ 
	public override void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps){
		DisableTeamPanel ();	//禁用队伍面板
		UpdateTeamPanel (true);	//根据当前玩家信息在队伍面板显示所有玩家信息(true表示显示本地玩家信息)
	}

	/**覆写IPunCallback回调函数,当MasterClient更变时调用
	 * 设置ReadyButton的按钮事件
	 */
	public override void OnMasterClientSwitched (PhotonPlayer newMasterClient) {
		ReadyButtonControl ();
	}

	/**覆写IPunCallback回调函数,当有玩家离开房间时调用
	 * 更新队伍面板中显示的玩家信息
	 */ 
	public override void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer){
		DisableTeamPanel ();	//唧哝队伍面板
		UpdateTeamPanel (true);	//根据当前玩家信息在队伍面板显示所有玩家信息(true表示显示本地玩家信息)
	}

	//禁用队伍面板
	void DisableTeamPanel(){
		for (int i = 0; i < Team1.Length; i++) {
			Team1 [i].SetActive (false);
		}
		for (int i = 0; i < Team2.Length; i++) {
			Team2 [i].SetActive (false);
		}
	}

	/**在队伍面板显示玩家信息
	 * 函数参数表示是否显示本地玩家信息
	 */
	void UpdateTeamPanel(bool isUpdateSelf){
		GameObject go;
		foreach (PhotonPlayer p in PhotonNetwork.playerList) {	//获取房间里所有玩家信息
			if (!isUpdateSelf && p.isLocal)	continue;			//判断是否更新本地玩家信息
			costomProperties = p.customProperties;				//获取玩家自定义属性
			if (costomProperties ["Team"].Equals ("Team1")) {	//判断玩家所属队伍
				go = Team1 [(int)costomProperties ["TeamNum"]];	//查询玩家的队伍序号
				go.SetActive (true);							//激活显示玩家信息的UI
				texts = go.GetComponentsInChildren<Text> ();	//获取显示玩家信息的Text组件
			} else {											
				go = Team2 [(int)costomProperties ["TeamNum"]];	
				go.SetActive (true);
				texts = go.GetComponentsInChildren<Text> ();
			}
			texts [0].text = p.name;						//显示玩家姓名
			if(p.isMasterClient)							//如果玩家是MasterClient
				texts[1].text="房主";						//玩家状态显示"房主"
			else if ((bool)costomProperties ["isReady"]) {	//如果玩家不是MasterClient,获取玩家的准备状态isReady
				texts [1].text = "已准备";					//isReady为true,显示"已准备"
			} else
				texts [1].text = "未准备";					//isReady为false,显示"未准备"
		}
	}

	//ReadyButton按钮事件设置
	void ReadyButtonControl(){
		if (PhotonNetwork.isMasterClient) {									//如果玩家是MasterClient
			readyButton.GetComponentInChildren<Text> ().text = "开始游戏";	//ReadyButton显示"开始游戏"
			readyButton.onClick.RemoveAllListeners ();						//移除ReadyButton所有监听事件
			readyButton.onClick.AddListener (delegate() {					//为ReadyButton绑定新的监听事件
				ClickStartGameButton ();									//开始游戏
			});
		} else {															//如果玩家不是MasterClient
			if((bool)PhotonNetwork.player.customProperties["isReady"])		//根据玩家准备状态显示对应的文本信息
				readyButton.GetComponentInChildren<Text> ().text = "取消准备";		
			else 
				readyButton.GetComponentInChildren<Text> ().text = "准备";
			readyButton.onClick.RemoveAllListeners ();						//移除ReadyButton所有监听事件
			readyButton.onClick.AddListener (delegate() {					//为ReadyButton绑定新的监听事件
				ClickReadyButton ();										//切换准备状态
			});
		}
	}

	//"切换队伍"按钮
	public void ClickSwitchButton(){
		costomProperties = PhotonNetwork.player.customProperties;	//获取玩家自定义属性
		if ((bool)costomProperties ["isReady"]) {					//如果玩家处于准备状态
			promptMessage.text="准备状态下不能切换队伍";				//提示信息显示玩家不能切换队伍
			return;													//结束函数的执行
		}
		bool isSwitched = false;		//标记玩家切换队伍是否成功,默认值表示不成功	
		if (costomProperties ["Team"].ToString ().Equals ("Team1")) {				//判断玩家队伍
			for (int i = 0; i < teamSize; i++) {									//寻找另一支队伍是否有空余位置
				if (!Team2 [i].activeSelf) {										//如果找到了空缺位置
					isSwitched = true;												//标记玩家切换队伍成功
					Team1 [(int)costomProperties ["TeamNum"]].SetActive (false);	//禁用之前显示玩家信息的UI
					texts = Team2 [i].GetComponentsInChildren<Text> ();				//获取切换队伍后,显示玩家信息的Text组件
					texts [0].text = PhotonNetwork.playerName;						//填入玩家昵称
					if(PhotonNetwork.isMasterClient)texts[1].text="房主";			//如果玩家是MasterClient,玩家状态显示"房主"
					else texts [1].text = "未准备";									//如果玩家不是MasterClient,玩家状态显示"未准备"
					Team2 [i].SetActive (true);										//激活显示玩家信息的UI
					costomProperties = new ExitGames.Client.Photon.Hashtable ()		//重新设置玩家的自定义属性
					{ { "Team","Team2" }, { "TeamNum",i } };
					PhotonNetwork.player.SetCustomProperties (costomProperties);	
					break;
				}
			}
		} else if (costomProperties ["Team"].ToString ().Equals ("Team2")) {		//判断玩家队伍
			for (int i = 0; i < teamSize; i++) {									//寻找另一支队伍是否有空余位置
				if (!Team1 [i].activeSelf) {										//如果找到了空缺位置
					isSwitched = true;												//标记玩家切换队伍成功
					Team2 [(int)(costomProperties ["TeamNum"])].SetActive (false);	//禁用之前显示玩家信息的UI
					texts = Team1 [i].GetComponentsInChildren<Text> ();				//获取切换队伍后,显示玩家信息的Text组件
					texts [0].text = PhotonNetwork.playerName;						//填入玩家昵称
					if(PhotonNetwork.isMasterClient)texts[1].text="房主";			//如果玩家是MasterClient,玩家状态显示"房主"
					else texts [1].text = "未准备";									//如果玩家不是MasterClient,玩家状态显示"未准备"
					Team1 [i].SetActive (true);										//激活显示玩家信息的UI
					costomProperties = new ExitGames.Client.Photon.Hashtable ()		//重新设置玩家的自定义属性
					{ { "Team","Team1" }, { "TeamNum",i } };
					PhotonNetwork.player.SetCustomProperties (costomProperties);
					break;
				}
			}
		}
		if (!isSwitched)
			promptMessage.text = "另一队伍已满,无法切换";	//如果玩家切换队伍失败,提示信息显示"另一队伍已满,无法切换"
		else
			promptMessage.text = "";
	}

	//准备按钮事件响应函数
	public void ClickReadyButton(){
		bool isReady = (bool)PhotonNetwork.player.customProperties ["isReady"];					//获取玩家准备状态
		costomProperties = new ExitGames.Client.Photon.Hashtable (){ { "isReady",!isReady } };	//重新设置玩家准备状态
		PhotonNetwork.player.SetCustomProperties (costomProperties);
		Text readyButtonText = readyButton.GetComponentInChildren<Text> ();	//获取ReadyButton的按钮文本
		if(isReady)readyButtonText.text="准备";		//根据玩家点击按钮后的状态,设置按钮文本的显示
		else readyButtonText.text="取消准备";
	}

	//开始游戏按钮事件响应函数
	public void ClickStartGameButton(){
		foreach (PhotonPlayer p in PhotonNetwork.playerList) {		//遍历房间内所有玩家
			if (p.isLocal) continue;								//不检查MasterClient房主的准备状态
			if ((bool)p.customProperties ["isReady"] == false) {	//如果有人未准备
				promptMessage.text = "有人未准备,游戏无法开始";		//提示信息显示"有人未准备,游戏无法开始"
				return;												//结束函数执行
			}
		}
		promptMessage.text = "";										//清空提示信息
		PhotonNetwork.room.open = false;								//设置房间的open属性,使游戏大厅的玩家无法加入此房间
		pView.RPC ("LoadGameScene", PhotonTargets.All, "GameScene");	//调用RPC,让游戏房间内所有玩家加载场景GameScene,开始游戏
	}

	//RPC函数,玩家加载场景
	[PunRPC]
	public void LoadGameScene(string sceneName){	
		PhotonNetwork.LoadLevel (sceneName);	//加载场景名为sceneName的场景
	}
}

5.玩家信息

using System.Collections;
using System;

public class PlayerInfo:IComparable<PlayerInfo>{	//PlayerInfo实现IComparable接口
	public string playerName;	//玩家姓名
	public int playerScore;		//玩家得分
		
	//无参构造函数
	public PlayerInfo(){
	}

	//构造函数:玩家姓名,玩家得分
	public PlayerInfo(string _playerName,int _playerScore){
		playerName = _playerName;
		playerScore = _playerScore;
	}

	//实现IComparable接口的CompareTo函数,完成PlayerInfo对象的比较
	public int CompareTo(PlayerInfo other){
		if (this.playerScore > other.playerScore)
			return 1;
		else if (this.playerScore == other.playerScore)
			return 0;
		else
			return -1;
	}
}
6.枪械同步
using UnityEngine;
using System.Collections;
using Photon;

public class GunController : PunBehaviour {

	Vector3 m_position;
	Quaternion m_rotation;
	float lerpSpeed = 10.0f;	//内插速度

	//初始化玩家位置与朝向
	void Start(){
		m_position = transform.position;	
		m_rotation = transform.rotation;
	}

	//序列化发送、获取数据
	void OnPhotonSerializeView(PhotonStream stream,PhotonMessageInfo info){
		if (stream.isWriting) 						//本地玩家发送数据
		{
			stream.SendNext (transform.position);
			stream.SendNext (transform.rotation);
		} 
		else 										//远程玩家接收数据
		{
			m_position = (Vector3)stream.ReceiveNext();
			m_rotation = (Quaternion)stream.ReceiveNext();
		}
	}

	void Update () {
		if (!photonView.isMine) 	//如果玩家对象不属于本地玩家,需要根据接收的数据更新玩家对象的位置与朝向
		{
			transform.position = Vector3.Lerp 		
				(transform.position, m_position, Time.deltaTime * lerpSpeed);	//使用Lerp函数实现玩家的平滑移动
			transform.rotation = Quaternion.Lerp 
				(transform.rotation, m_rotation, Time.deltaTime * lerpSpeed);	//使用Lerp函数实现玩家的平滑转动
		}
	}

}

7.游戏管理器

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Photon;
using UnityEngine.UI;
public class GameManager : PunBehaviour {
	public static GameManager gm;		//GameManager静态实例

	public enum GameState{		//游戏状态枚举
		PreStart,				//游戏开始前
		Playing,				//游戏进行中
		GameWin,				//游戏胜利
		GameLose,				//游戏失败
		Tie};					//平手
	public GameState state = GameState.PreStart;	//初始化游戏状态
	public Transform[] teamOneSpawnTransform;		//队伍1出生位置
	public Transform[] teamTwoSpawnTransform;		//队伍2出生位置
	public float checkplayerTime = 5.0f;			//检查玩家加载场景时间
	public float gamePlayingTime = 600.0f;			//游戏时间
	public float gameOverTime = 10.0f;				//游戏结束时间
	public float spawnTime = 5.0f;					//重生时间
	public int targetScore = 50;					//目标分数
	public Text timeLabel;							//倒计时时间显示
	public Text targetScoreLabel;					//目标分数显示

	//实时计分板
	public Text Team1RealTimeScorePanelScore;
	public Text Team2RealTimeScorePanelScore;

	public GameObject scorePanel;				//玩家得分榜
	public Text teamOneTotal;					//队伍1总分
	public Text teamTwoTotal;					//队伍2总分
	public GameObject[] teamOneScorePanel;		//队伍1成员得分面板
	public GameObject[] teamTwoScorePanel;		//队伍2成员得分面板
	public Text gameResult;						//游戏结束信息
	public Slider hpSlider;						//玩家血条
	public AudioClip gameStartAudio;			//游戏开始音效
	public AudioClip gameWinAudio;				//游戏胜利音效
	public AudioClip gameLoseAudio;				//游戏失败音效
	public AudioClip tieAudio;					//平手音效

	double startTimer = 0;			//倒计时开始时间
	double endTimer = 0;			//倒计时结束时间
	double countDown = 0;			//倒计时
	int loadedPlayerNum = 0;		//已加载场景的玩家个数
	int currentScoreOfTeam1 = 0;	//队伍1得分
	int currentScoreOfTeam2 = 0;	//队伍2得分
	const float photonCircleTime = 4294967.295f;	//Photon服务器循环时间

	Camera mainCamera;
	GameObject localPlayer = null;
	ExitGames.Client.Photon.Hashtable playerCustomProperties;
	PlayerHealth playerHealth;

	//初始化
	void Start () {
		gm = GetComponent<GameManager> ();		//初始化GameManager静态实例gm
		mainCamera = Camera.main;				//获取摄像机
		photonView.RPC ("ConfirmLoad", PhotonTargets.All);				//使用RPC,告知所有玩家有一名玩家已成功加载场景
		playerCustomProperties = new ExitGames.Client.Photon.Hashtable{ { "Score",0 } };	//初始化玩家得分
		PhotonNetwork.player.SetCustomProperties (playerCustomProperties);	
		targetScoreLabel.text = "目标得分:" + targetScore.ToString ();	//显示目标分数
		//初始化队伍得分
		currentScoreOfTeam1 = 0;										
		currentScoreOfTeam2 = 0;
		UpdateScores (currentScoreOfTeam1, currentScoreOfTeam2);		//更新玩家得分榜
		if (PhotonNetwork.isMasterClient)								//MasterClient设置游戏开始倒计时
			photonView.RPC ("SetTime", PhotonTargets.All, PhotonNetwork.time, checkplayerTime);
		gameResult.text = "";					//清空游戏结果
		scorePanel.SetActive (false);			//禁用玩家得分榜
	}

	//RPC函数,增加成功加载场景的玩家个数
	[PunRPC]
	void ConfirmLoad(){
		loadedPlayerNum++;
	}

	//每帧执行一次,更新倒计时,控制游戏状态
	void Update(){
		countDown = endTimer - PhotonNetwork.time;	//计算倒计时
		if (countDown >= photonCircleTime)			//防止entTimer值超过Photon服务器循环时间,确保倒计时能正确结束
			countDown -= photonCircleTime;
		UpdateTimeLabel ();							//更新倒计时的显示

		//游戏状态控制
		switch (state) {
		//如果游戏处于游戏开始前
		case GameState.PreStart:					
			if (PhotonNetwork.isMasterClient) {		//MasterClient检查倒计时和场景加载人数,控制游戏开始
				CheckPlayerConnected ();
			}
			break;
		//如果游戏处于游戏进行中
		case GameState.Playing:				
			hpSlider.value = playerHealth.currentHP;			//更新玩家生命值血条的显示
			#if(!UNITY_ANDROID)
			scorePanel.SetActive (Input.GetKey (KeyCode.Tab));	//PC使用Tab键显示玩家得分榜
			#endif
			if (PhotonNetwork.isMasterClient) {					//MasterClient检查游戏状态
				if (currentScoreOfTeam1 >= targetScore)			//队伍1达到目标分数,队伍1获胜
					photonView.RPC ("EndGame", PhotonTargets.All, "Team1",PhotonNetwork.time);
				else if (currentScoreOfTeam2 >= targetScore)	//队伍2达到目标分数,队伍2获胜
					photonView.RPC ("EndGame", PhotonTargets.All, "Team2",PhotonNetwork.time);
				else if (countDown <= 0.0f) {					//游戏倒计时结束,得分高的队伍获胜
					if (currentScoreOfTeam1 > currentScoreOfTeam2)		
						photonView.RPC ("EndGame", PhotonTargets.All, 
							"Team1", PhotonNetwork.time);
					else if (currentScoreOfTeam1 < currentScoreOfTeam2)
						photonView.RPC ("EndGame", PhotonTargets.All, 
							"Team2",PhotonNetwork.time);
					else                                        //双方得分相同,平手
						photonView.RPC ("EndGame", PhotonTargets.All, 
							"Tie",PhotonNetwork.time);
				}
			}
			break;
		case GameState.GameWin:		//游戏胜利状态,倒计时结束,退出游戏房间
			if (countDown <= 0)
				LeaveRoom ();
			break;
		case GameState.GameLose:	//游戏结束状态,倒计时结束,退出游戏房间
			if (countDown <= 0)
				LeaveRoom ();
			break;
		case GameState.Tie:
			if (countDown <= 0)		//平手状态,倒计时结束,退出游戏房间
				LeaveRoom ();
			break;
		}
	}

	/**IPunCallback回调函数,有玩家断开连接时(离开房间)调用
	 * MasterClient检查双方人数,更新玩家得分榜的显示
	 */
	public override void OnPhotonPlayerDisconnected(PhotonPlayer other){
		if (state != GameState.Playing)		//游戏状态不是游戏进行中,结束函数执行
			return;
		if (PhotonNetwork.isMasterClient) {	//MasterClient检查
			CheckTeamNumber ();				//检查两队人数
			//更新玩家得分榜
			photonView.RPC ("UpdateScores", PhotonTargets.All, currentScoreOfTeam1, currentScoreOfTeam2);
		}
	}

	/**检查加载场景的玩家个数
	 * 该函数只由MasterClient调用
	 */
	void CheckTeamNumber(){
		PhotonPlayer[] players = PhotonNetwork.playerList;		//获取房间内玩家列表
		int teamOneNum = 0, teamTwoNum = 0;						
		foreach (PhotonPlayer p in players) {					//遍历所有玩家,计算两队人数
			if (p.customProperties ["Team"].ToString () == "Team1")
				teamOneNum++;
			else
				teamTwoNum++;
		}
		//如果有某队伍人数为0,另一队获胜
		if (teamOneNum == 0)
			photonView.RPC ("EndGame", PhotonTargets.All, "Team2",PhotonNetwork.time);
		else if (teamTwoNum == 0)
			photonView.RPC ("EndGame", PhotonTargets.All, "Team1",PhotonNetwork.time);
	}

	//显示两队实时分数
	void UpdateRealTimeScorePanel()
	{
		string team1Title = string.Empty;
		string team2Title = string.Empty;

		team1Title = string.Format("得分:{0}",currentScoreOfTeam1);
		team2Title = string.Format("得分:{0}",currentScoreOfTeam2);

		Team1RealTimeScorePanelScore.text = team1Title;
		Team2RealTimeScorePanelScore.text = team2Title;
	}

	//显示倒计时时间
	void UpdateTimeLabel(){
		int minute = (int)countDown / 60;
		int second = (int)countDown % 60;
		timeLabel.text = minute.ToString ("00") + ":" + second.ToString ("00");
	}

	//检查所有玩家是否已经加载场景
	void CheckPlayerConnected(){
		if (countDown <=0.0f || loadedPlayerNum == PhotonNetwork.playerList.Length) {	//游戏开始倒计时结束,或者所有玩家加载场景
			startTimer = PhotonNetwork.time;								//游戏开始时间(使用Photon服务器的时间)
			photonView.RPC ("StartGame",PhotonTargets.All,startTimer);		//使用RPC,所有玩家开始游戏
		}
	}

	//RPC函数,开始游戏
	[PunRPC]
	void StartGame(double timer){
		SetTime(timer,gamePlayingTime);	//设置游戏进行倒计时时间
		gm.state = GameState.Playing;	//游戏状态切换到游戏进行状态
		InstantiatePlayer ();			//创建玩家对象
		AudioSource.PlayClipAtPoint(gameStartAudio, localPlayer.transform.position);	//播放游戏开始音效
	}

	//RPC函数,设置倒计时时间
	[PunRPC]
	void SetTime(double sTime,float dTime){
		startTimer = sTime;
		endTimer = sTime + dTime;
	}

	//生成玩家对象
	void InstantiatePlayer(){
		playerCustomProperties= PhotonNetwork.player.customProperties;	//获取玩家自定义属性
		//如果玩家属于队伍1,生成EthanPlayer对象
		if (playerCustomProperties ["Team"].ToString ().Equals ("Team1")) {	
			localPlayer = PhotonNetwork.Instantiate ("EthanPlayer", 
				teamOneSpawnTransform [(int)playerCustomProperties ["TeamNum"]].position, Quaternion.identity, 0);
		}
		//如果玩家属于队伍2,生成RobotPlayer对象
		else if (PhotonNetwork.player.customProperties ["Team"].ToString ().Equals ("Team2")) {
			localPlayer = PhotonNetwork.Instantiate ("RobotPlayer", 
				teamTwoSpawnTransform [(int)playerCustomProperties ["TeamNum"]].position, Quaternion.identity, 0);
		}
		localPlayer.GetComponent<PlayerMove> ().enabled = true;					//启用PlayerMove脚本,使玩家对象可以被本地客户端操控
		PlayerShoot playerShoot = localPlayer.GetComponent<PlayerShoot> ();		//获取玩家对象的PlayerShoot脚本
		playerHealth = localPlayer.GetComponent<PlayerHealth> ();				//获取玩家对象的PlayerHealth脚本
		hpSlider.maxValue = playerHealth.maxHP;									//设置显示玩家血量的Slider控件
		hpSlider.minValue = 0;
		hpSlider.value = playerHealth.currentHP;
		Transform tempTransform = localPlayer.transform;
		mainCamera.transform.parent = tempTransform;							//将场景中的摄像机设为玩家对象的子对象
		mainCamera.transform.localPosition = playerShoot.shootingPosition;		//设置摄像机的位置,为PlayerShoot脚本中的射击起始位置
		mainCamera.transform.localRotation = Quaternion.identity;				//设置摄像机的朝向
		for (int i = 0; i < tempTransform.childCount; i++) {					//将枪械对象设为摄像机的子对象
			if (tempTransform.GetChild (i).name.Equals ("Gun")) {
				tempTransform.GetChild (i).parent = mainCamera.transform;
				break;
			}
		}
	}

	/**玩家得分增加函数
	 * 该函数只由MasterClient调用
	 */
	public void AddScore(int killScore, PhotonPlayer p){
		if (!PhotonNetwork.isMasterClient)		//如果函数不是由MasterClient调用,结束函数执行
			return;
		int score = (int)p.customProperties ["Score"];		//获取击杀者玩家得分
		score += killScore;									//增加击杀者玩家得分
		playerCustomProperties = new ExitGames.Client.Photon.Hashtable{ { "Score",score } };
		p.SetCustomProperties (playerCustomProperties);
		if (p.customProperties ["Team"].ToString () == "Team1")
			currentScoreOfTeam1 += killScore;		//增加队伍1总分
		else
			currentScoreOfTeam2 += killScore;		//增加队伍2总分
		//使用RPC,更新所有客户端的玩家得分榜
		photonView.RPC ("UpdateScores",PhotonTargets.All,currentScoreOfTeam1,currentScoreOfTeam2);
	}

	//RPC函数,更新玩家得分榜
	[PunRPC]
	void UpdateScores(int teamOneScore,int teamTwoScore){
		//禁用所有显示玩家得分的条目
		foreach (GameObject go in teamOneScorePanel)
			go.SetActive (false);
		foreach (GameObject go in teamTwoScorePanel)
			go.SetActive (false);

		//更新队伍1、队伍2的总分
		currentScoreOfTeam1 = teamOneScore;		
		currentScoreOfTeam2 = teamTwoScore;
		PhotonPlayer[] players = PhotonNetwork.playerList;	//获取房间内所有玩家的信息
		List<PlayerInfo> teamOne = new List<PlayerInfo>();
		List<PlayerInfo> teamTwo = new List<PlayerInfo>();
		PlayerInfo tempPlayer;
		//遍历房间内所有玩家,将他们的得分根据他们的队伍放入对应的队伍列表中
		foreach (PhotonPlayer p in players) {
			tempPlayer = new PlayerInfo (p.name, (int)p.customProperties ["Score"]);
			if (p.customProperties ["Team"].ToString () == "Team1")
				teamOne.Add (tempPlayer);
			else
				teamTwo.Add (tempPlayer);
		}
		//分别对两队队伍列表排序,按照分数从大到小排序
		teamOne.Sort ();
		teamTwo.Sort ();
		Text[] texts;
		int length = teamOne.Count;
		//依次在玩家得分榜显示两队玩家得分,保证得分高的玩家在得分低的玩家之上
		for (int i = 0; i < length; i++) {
			texts = teamOneScorePanel [i].GetComponentsInChildren<Text> ();
			texts [0].text = teamOne [i].playerName;
			texts [1].text = teamOne [i].playerScore.ToString();
			teamOneScorePanel [i].SetActive (true);
		}
		length = teamTwo.Count;
		for (int i = 0; i < length; i++) {
			texts = teamTwoScorePanel [i].GetComponentsInChildren<Text> ();
			texts [0].text = teamTwo [i].playerName;
			texts [1].text = teamTwo [i].playerScore.ToString();
			teamTwoScorePanel [i].SetActive (true);
		}
		//显示两队得分
		teamOneTotal.text = "Team1:" + currentScoreOfTeam1.ToString ();
		teamTwoTotal.text = "Team2:" + currentScoreOfTeam2.ToString ();
		UpdateRealTimeScorePanel();		//更新实时得分榜
	}

	//游戏结束,更改客户端的游戏状态
	[PunRPC]
	void EndGame(string winTeam,double timer){
		//如果两队不是平手,游戏结束信息显示获胜队伍胜利
		if (winTeam != "Tie")
			gameResult.text = winTeam + " Wins!";
		if (winTeam == "Tie") 			//如果两队打平
		{	
			gm.state = GameState.Tie;	//游戏状态切换为平手状态
			AudioSource.PlayClipAtPoint (tieAudio, localPlayer.transform.position);	//播放平手音效
			gameResult.text = "Tie!";	//游戏结束信息显示"Tie!"表示平手
		} 
		else if (winTeam == PhotonNetwork.player.customProperties ["Team"].ToString ()) 	//如果玩家属于获胜队伍
		{
			gm.state = GameState.GameWin;		//游戏状态切换为游戏胜利状态
			//播放游戏胜利音效
			AudioSource.PlayClipAtPoint (gameWinAudio,localPlayer.transform.position);
		} 
		else //如果玩家属于失败队伍
		{
			gm.state = GameState.GameLose;		//游戏状态切换为游戏失败状态
			//播放游戏失败音效
			AudioSource.PlayClipAtPoint (gameLoseAudio, localPlayer.transform.position);
		}

		scorePanel.SetActive(true);		//游戏结束后,显示玩家得分榜
		SetTime (timer, gameOverTime);	//设置游戏结束倒计时时间
	}

	//本地玩家加分
	public void localPlayerAddHealth(int points){
		PlayerHealth ph = localPlayer.GetComponent<PlayerHealth> ();
		ph.requestAddHP (points);
	}

	//如果玩家断开与Photon服务器的连接,加载场景GameLobby
	public override void OnConnectionFail(DisconnectCause cause){
		PhotonNetwork.LoadLevel ("GameLobby");
	}

	//显示玩家得分榜,用于移动端的得分榜按钮,代替PC的Tab键
	public void ShowScorePanel(){
		scorePanel.SetActive (!scorePanel.activeSelf);
	}

	//离开房间函数
	public void LeaveRoom(){
		PhotonNetwork.LeaveRoom ();				//玩家离开游戏房间
		PhotonNetwork.LoadLevel ("GameLobby");	//加载场景GameLobby
	}
}

猜你喜欢

转载自blog.csdn.net/qq_27012963/article/details/80274314