NetworkManager网络通讯_NetworkManager(二)
本文主要来实现一下自定UI(实现HUD的功能),并对Network Manger进行深入的讲解。
1)自定义manager
创建脚本CustomerUnetManger,并继承自NetworkManger,并对相关虚函数进行重载,并简单写了几个外部调用方法。完整脚本在文末,部分截图如下:
其中LogInfo为debug用,完整脚本在文末
2)UI脚本CustomerUnetMainMenu
编写脚本,实现自定义新建Server client 以及host,再次着重说一下原NetworkMangerHUD脚本中的第四个方法,即NetworkManger中的matchmaker。matchmaker通过unity提供的网络服务,建立游戏,然后通过你自己生成的exe就可以获取到建立的游戏列表,然后可以加入游戏:
首先开启matchmaker
/// <summary> /// UI调用,MatchMaker /// </summary> public void StartMatchMaker_() { if (!IsClientConnected() && !NetworkServer.active && matchMaker == null) { StartMatchMaker(); matchMode = true; } }
然后建立游戏
/// <summary> /// UI调用,创建比赛 /// </summary> public void CreateMatch_() { if (matchMaker != null) { matchMaker.CreateMatch("LLMatch", 3, true, "", "", "", 0, 0, OnMatchCreate); } }
获取游戏列表(获取列表并UI显示时需要脚本match Button)
matchMaker.ListMatches(0, 5, "", true, 0, 0, OnMatchList);
加入游戏
/// <summary> /// 加入指定的比赛 /// 对于建立比赛的player,本身已经在游戏中,所以不能再次加入(已经生成host) /// 对于建立比赛的player,在加入其他游戏时先取消比赛(DestroyMatch) /// 对于加入比赛的player,只能加入一次,不能重复加入(已经生成client) /// 对于加入比赛的Player,在重复加入或者加入其他游戏之前先断开连接(DropConnection) /// 本程序为demo,上述问题不做处理 /// </summary> /// <param name="jointMatch"></param> public void JoinMatch(MatchInfoSnapshot jointMatch) { if (matchMaker == null) StartMatchMaker(); matchMaker.JoinMatch(jointMatch.networkId, "", "", "", 0, 0, OnMatchJoined);//调用此方法时生成client }
3)此部分到此基本结束没有太大问题,一些注意事项已经在代码中注释,至于如何退出比赛等会再下一篇LobbyManager中进行解释,下边时此工程的所有脚本文件。再次说明一下,玩家预制体等均采用上一篇。此工程为demo,所以UI简陋,可能会有不友好的操作或者逻辑bug
//——————————————————————————————脚本————————————————————————————//
using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Networking.Match; public class CustomerUnetManger : NetworkManager { public Action<List<MatchInfoSnapshot>> ListMatchAction; private float refreshTime = 0; private bool matchMode = false; #region SERVER CALLBACKS public override void OnServerReady(NetworkConnection conn) { LogInfo.theLogger.Log("Server ready"); base.OnServerReady(conn); } public override void OnStartServer() { LogInfo.theLogger.Log("Server start"); base.OnStartServer(); } public override void OnServerConnect(NetworkConnection conn) { LogInfo.theLogger.Log("Server connect"); base.OnServerConnect(conn); } public override void OnServerDisconnect(NetworkConnection conn) { LogInfo.theLogger.Log("Server disconnect"); base.OnServerDisconnect(conn); } public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId) { LogInfo.theLogger.Log("Server add player"); base.OnServerAddPlayer(conn, playerControllerId); } public override void OnServerRemovePlayer(NetworkConnection conn, PlayerController player) { LogInfo.theLogger.Log("Server remove player"); base.OnServerRemovePlayer(conn, player); } public override void OnServerError(NetworkConnection conn, int errorCode) { LogInfo.theLogger.Log("Server error"); base.OnServerError(conn, errorCode); } public override void OnStartHost() { LogInfo.theLogger.Log("Host start"); base.OnStartHost(); } public override void OnStopHost() { LogInfo.theLogger.Log("Host stop"); base.OnStopHost(); } public override void OnStopServer() { LogInfo.theLogger.Log("Server stop"); base.OnStopServer(); } #endregion #region CLIENT CALLBACKS public override void OnClientConnect(NetworkConnection conn) { LogInfo.theLogger.Log("Client connect"); base.OnClientConnect(conn); } public override void OnClientDisconnect(NetworkConnection conn) { LogInfo.theLogger.Log("Client disconnect"); base.OnClientDisconnect(conn); } public override void OnClientError(NetworkConnection conn, int errorCode) { LogInfo.theLogger.Log("Client error"); base.OnClientError(conn, errorCode); } public override void OnStartClient(NetworkClient client) { LogInfo.theLogger.Log("Client start"); base.OnStartClient(client); } public override void OnStopClient() { LogInfo.theLogger.Log("Client stop"); base.OnStopClient(); } #endregion #region MATCHMAKER CALLBACKS public override void OnMatchCreate(bool success, string extendedInfo, MatchInfo matchInfo) { LogInfo.theLogger.Log("Match create"); //MatchCreate结束后进行OnMatchCreate回调,而在base中OnMatchCreate时会 //立马创建host(即创建一个server和client),所以当重复创建match时报错 //为避免此类问题可以在OnMatchCreate中不调用base的OnMatchCreate,通过自行创建List<MatchInfoSnapshot>变量自己存储比赛(matches) //然后在需要创建host时,再startHost,但是一般游戏时只允许玩家创建一个游戏,创建另一个游戏时需退出当前游戏 base.OnMatchCreate(success, extendedInfo, matchInfo); matchMaker.ListMatches(0, 5, "", true, 0, 0, OnMatchList); } public override void OnMatchJoined(bool success, string extendedInfo, MatchInfo matchInfo) { LogInfo.theLogger.Log("Match joint"); base.OnMatchJoined(success, extendedInfo, matchInfo); } public override void OnMatchList(bool success, string extendedInfo, List<MatchInfoSnapshot> matchList) { LogInfo.theLogger.Log("Match list:"+ matchList.Count);//基函数的OnMatchList把matchList赋值给matches,此处matches仍为初始值 base.OnMatchList(success, extendedInfo, matchList); if(ListMatchAction!=null) { ListMatchAction(matchList); } //LogInfo.theLogger.Log("Match list:" + matches.Count); } #endregion #region CONTROLL METHODS /// <summary> /// UI调用,开启server /// </summary> public void StartServer_() { if (!IsClientConnected() && !NetworkServer.active && matchMaker == null) { StartServer(); } } /// <summary> /// UI调用,开启Host /// </summary> public void StartHost_() { if (!IsClientConnected() && !NetworkServer.active && matchMaker == null) { StartHost(); } } /// <summary> /// UI调用,开启client /// </summary> public void StartClient_() { if (!IsClientConnected() && !NetworkServer.active && matchMaker == null) { StartClient(); } } /// <summary> /// UI调用,MatchMaker /// </summary> public void StartMatchMaker_() { if (!IsClientConnected() && !NetworkServer.active && matchMaker == null) { StartMatchMaker(); matchMode = true; } } /// <summary> /// UI调用,停止服务 /// </summary> public void StopAllService() { if (NetworkServer.active || IsClientConnected()) { StopHost(); } if (client != null && NetworkClient.active) { StopClient(); } if (matchMaker != null) { StopMatchMaker(); matchMode = false; } } /// <summary> /// UI调用,创建比赛 /// </summary> public void CreateMatch_() { if (matchMaker != null) { matchMaker.CreateMatch("LLMatch", 3, true, "", "", "", 0, 0, OnMatchCreate); } } /// <summary> /// 加入指定的比赛 /// 对于建立比赛的player,本身已经在游戏中,所以不能再次加入(已经生成host) /// 对于建立比赛的player,在加入其他游戏时先取消比赛(DestroyMatch) /// 对于加入比赛的player,只能加入一次,不能重复加入(已经生成client) /// 对于加入比赛的Player,在重复加入或者加入其他游戏之前先断开连接(DropConnection) /// 本程序为demo,上述问题不做处理 /// </summary> /// <param name="jointMatch"></param> public void JoinMatch(MatchInfoSnapshot jointMatch) { if (matchMaker == null) StartMatchMaker(); matchMaker.JoinMatch(jointMatch.networkId, "", "", "", 0, 0, OnMatchJoined);//调用此方法时生成client } #endregion private void Update() { //取消了实时更新列表,可以测试使用 //if(Time.time>refreshTime && matchMode) //{ // if (matchMaker == null) StartMatchMaker(); // matchMaker.ListMatches(0, 5, "", true, 0, 0, OnMatchList); // refreshTime += 4; //} } }
using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Networking.Match; using UnityEngine.UI; public class CustomerUnetMainMenu : MonoBehaviour { public Button serverButton; public Button hostButton; public Button clinetButton; public Button matchMakerButton; public Button stopButton; public Button createMatchButton; public GameObject starts; public GameObject matches; public CustomerUnetManger theManager; public MatchListRefresher refresher; private bool matchCreated = false; #region BUTTON METHODS private void StartServer() { theManager.StartServer_(); } private void StartHost() { theManager.StartHost_(); } private void StartClient() { theManager.StartClient_(); } private void StartMatchMaker() { theManager.StartMatchMaker_(); matches.SetActive(true); starts.SetActive(false); } private void Stop() { theManager.StopAllService(); matches.SetActive(false); starts.SetActive(true); matchCreated = false; } private void CreateMatch() { if(!matchCreated) { theManager.CreateMatch_(); matchCreated = true; } } #endregion private void Start() { serverButton.onClick.AddListener(StartServer); hostButton.onClick.AddListener(StartHost); clinetButton.onClick.AddListener(StartClient); matchMakerButton.onClick.AddListener(StartMatchMaker); stopButton.onClick.AddListener(Stop); createMatchButton.onClick.AddListener(CreateMatch); theManager.ListMatchAction += OnListMatch; } private void OnListMatch(List<MatchInfoSnapshot> list) { refresher.RefreshList(list); } }
using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking.Match; public class MatchListRefresher : MonoBehaviour { [SerializeField] private GameObject matchButton; //直接清除列表的刷新的方式不好,可通过一下两种方法解决: //1、增加本地存储matches,针对每次反馈的matches比对,只实例化增加或者销毁不存在的 //2、或者每次增加或者减少比赛,可以尝试让服务端调用每个客户端执行 public void RefreshList(List<MatchInfoSnapshot> matches) { ClearList(); foreach(var match in matches) { var button = Instantiate(matchButton, transform); button.GetComponent<MatchButton>().Initialize(match); } } private void ClearList() { foreach(Transform t in transform) { Destroy(t.gameObject); } } }
using UnityEngine; using UnityEngine.Networking; using UnityEngine.Networking.Match; using UnityEngine.UI; public class MatchButton : MonoBehaviour { private MatchInfoSnapshot match; //private NetworkManager manager; public void Initialize(MatchInfoSnapshot match) { this.match = match; GetComponentInChildren<Text>().text = match.name; GetComponent<Button>().onClick.AddListener(() => { //manager.matchMaker.JoinMatch(match); FindObjectOfType<CustomerUnetManger>().JoinMatch(match); }); } }
using UnityEngine; using UnityEngine.UI; public class LogInfo : MonoBehaviour { public bool isDebug = true; private Text log; public static LogInfo theLogger; public void Log(string info) { if(isDebug) log.text += "\r\n" + info; } private void Clear() { log.text = "Log:"; } void Start () { theLogger = this; log = GetComponent<Text>(); log.text = "Log:"; GetComponentInChildren<Button>().onClick.AddListener(Clear); } }