任务24:前端-匹配进入游戏房间显示匹配信息开发
前端大厅点击进入进入斗地主按钮,向服务端请求匹配进入房间。
//发送开始匹配消息 C2G_StartMatch_Req c2G_StartMatch_Req = new C2G_StartMatch_Req(); G2C_StartMatch_Back g2C_StartMatch_Ack = (G2C_StartMatch_Back)await SessionComponent.Instance.Session.Call(c2G_StartMatch_Req);
收到匹配返回后,前端就会切换到房间界面。
\Assets\Model\Landlords\LandUI\LandLoggy\LandLobbyComponent.cs
LandLobbyComponent组件awaki方法中增加匹配进入房间事件与事件方法
//匹配进入房间按钮 rc.Get<GameObject>("Landlords").GetComponent<Button>().onClick.Add(OnStartMatchLandlords);
/// <summary> /// 匹配斗地主 /// </summary> public async void OnStartMatchLandlords() { try { //发送开始匹配消息 C2G_StartMatch_Req c2G_StartMatch_Req = new C2G_StartMatch_Req(); G2C_StartMatch_Back g2C_StartMatch_Ack = (G2C_StartMatch_Back)await SessionComponent.Instance.Session.Call(c2G_StartMatch_Req); if (g2C_StartMatch_Ack.Error == ErrorCode.ERR_UserMoneyLessError) { Log.Error("余额不足"); return; } //切换到房间界面 UI landRoom = Game.Scene.GetComponent<UIComponent>().Create(LandUIType.LandRoom); Game.Scene.GetComponent<UIComponent>().Remove(LandUIType.LandLobby); } catch (Exception e) { Log.Error(e); } }
\Assets\Model\Landlords\LandUI\UIEventType.cs
FUIType增加LandRoom
public static partial class LandUIType { public const string LandLogin = "LandLogin"; public const string LandLobby = "LandLobby"; public const string SetUserInfo = "SetUserInfo"; public const string LandRoom = "LandRoom"; }
LandUI目录下增加房间的界面组件与工厂方法
暂时房间界面只有准备游戏与离开房间按钮,还有个提示文本,准备游戏按钮是隐藏的
上节下载的前端起始项目,没有离开房间按钮,大家自己做一下。
准备了一个本节可用的简单的LandRoom0界面,后面节会有更完整的记得替换。
\Assets\Model\Landlords\LandUI\LandRoom\
LandRoomComponent.cs
using System; using ETModel; using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; namespace ETModel { [ObjectSystem] public class LandRoomComponentAwakeSystem : AwakeSystem<LandRoomComponent> { public override void Awake(LandRoomComponent self) { self.Awake(); } } /// <summary> /// 大厅界面组件 /// </summary> public class LandRoomComponent : Component { public readonly Dictionary<long, int> seats = new Dictionary<long, int>(); public bool Matching { get; set; } public readonly Gamer[] gamers = new Gamer[3]; public Text prompt; public void Awake() { ReferenceCollector rc = this.GetParent<UI>().GameObject.GetComponent<ReferenceCollector>(); GameObject quitButton = rc.Get<GameObject>("Quit"); GameObject readyButton = rc.Get<GameObject>("Ready"); prompt = rc.Get<GameObject>("MatchPrompt").GetComponent<Text>(); readyButton.SetActive(false); //默认隐藏 Matching = true; //进入房间后取消匹配状态 //绑定事件 quitButton.GetComponent<Button>().onClick.Add(OnQuit); readyButton.GetComponent<Button>().onClick.Add(OnReady); } public void AddGamer(Gamer gamer, int index) { seats.Add(gamer.UserID,index); gamers[index] = gamer; prompt.text = $"一位玩家进入房间,房间人数{seats.Count}"; } public void RemoveGamer(long id) { int seatIndex = GetGamerSeat(id); if (seatIndex >= 0) { Gamer gamer = gamers[seatIndex]; gamers[seatIndex] = null; seats.Remove(id); gamer.Dispose(); prompt.text = $"一位玩家离开房间,房间人数{seats.Count}"; } } public int GetGamerSeat(long id) { int seatIndex; if (seats.TryGetValue(id, out seatIndex)) { return seatIndex; } return -1; } public void OnQuit() { //发送退出房间消息 SessionComponent.Instance.Session.Send(new C2G_ReturnLobby_Ntt()); //切换到大厅界面 Game.Scene.GetComponent<UIComponent>().Create(LandUIType.LandLobby); Game.Scene.GetComponent<UIComponent>().Remove(LandUIType.LandRoom); } private void OnReady() { //发送准备 //SessionComponent.Instance.Session.Send(new Actor_GamerReady_Landlords()); } public override void Dispose() { if (this.IsDisposed) { return; } base.Dispose(); this.Matching = false; this.seats.Clear(); for (int i = 0; i < this.gamers.Length; i++) { if (gamers[i] != null) { gamers[i].Dispose(); gamers[i] = null; } } } } }
LandRoomFactory.cs
using ETModel; using System; using UnityEngine; namespace ETModel { [UIFactory(LandUIType.LandRoom)] public class LandRoomFactory : IUIFactory { public UI Create(Scene scene, string type, GameObject parent) { try { //加载AB包 ResourcesComponent resourcesComponent = ETModel.Game.Scene.GetComponent<ResourcesComponent>(); resourcesComponent.LoadBundle($"{type}.unity3d"); //加载大厅界面预设并生成实例 GameObject bundleGameObject = (GameObject)resourcesComponent.GetAsset($"{type}.unity3d", $"{type}"); GameObject landRoom = UnityEngine.Object.Instantiate(bundleGameObject); //设置UI层级,只有UI摄像机可以渲染 landRoom.layer = LayerMask.NameToLayer(LayerNames.UI); UI ui = ComponentFactory.Create<UI, GameObject>(landRoom); ui.AddComponent<LandRoomComponent>(); return ui; } catch (Exception e) { Log.Error(e); return null; } } public void Remove(string type) { ETModel.Game.Scene.GetComponent<ResourcesComponent>().UnloadBundle($"{type}.unity3d"); } } }
增加 Actor_GamerEnterRoom_NttHandler
收到Actor_GamerEnterRoom消息,隐藏提示文本,显示准备游戏按钮
\Assets\Model\Landlords\Handler\Actor_GamerEnterRoom_NttHandler.cs
using UnityEngine; using UnityEngine.UI; namespace ETModel { [MessageHandler] public class Actor_GamerEnterRoom_NttHandler : AMHandler<Actor_GamerEnterRoom_Ntt> { protected override async ETTask Run(ETModel.Session session, Actor_GamerEnterRoom_Ntt message) { UI uiRoom = Game.Scene.GetComponent<UIComponent>().Get(LandUIType.LandRoom); LandRoomComponent landRoomComponent = uiRoom.GetComponent<LandRoomComponent>(); //从匹配状态中切换为准备状态 if (landRoomComponent.Matching) { landRoomComponent.Matching = false; //进入房间取消匹配状态 GameObject matchPrompt = uiRoom.GameObject.Get<GameObject>("MatchPrompt"); uiRoom.GameObject.Get<GameObject>("Ready").SetActive(true); } //添加未显示玩家 for (int i = 0; i < message.Gamers.Count; i++) { //如果服务端发来了默认空GamerInfo 跳过 GamerInfo gamerInfo = message.Gamers[i]; if (gamerInfo.UserID == 0) continue; Gamer gamer = ETModel.ComponentFactory.Create<Gamer, long>(gamerInfo.UserID); landRoomComponent.AddGamer(gamer, i); } await ETTask.CompletedTask; } } }
现在可以运行前后端检查前后端请求与返回是否正常。
前端有报错10017消息指令没处理,需要在前端增加此消息的处理Handler
暂时还没什么用,只是通知前端有人进入或移除了匹配队列。
\Assets\Model\Landlords\Handler\LandlordsMatcherPlusOne_Handler.cs
using System; using System.Collections.Generic; using Google.Protobuf; using UnityEngine; namespace ETModel { [MessageHandler] public class LandMatcherPlusOne_Handler : AMHandler<Actor_LandMatcherPlusOne_NTT> { protected override async ETTask Run(ETModel.Session session, Actor_LandMatcherPlusOne_NTT message) { Log.Debug("匹配玩家+1"); await ETTask.CompletedTask; } } }
\Assets\Model\Landlords\Handler\LandlordsMatcherReduceOne_Handler.cs
using System; using System.Collections.Generic; using Google.Protobuf; using UnityEngine; namespace ETModel { [MessageHandler] public class LandMatcherReduceOne_Handler : AMHandler<Actor_LandMatcherReduceOne_NTT> { protected override async ETTask Run(ETModel.Session session, Actor_LandMatcherReduceOne_NTT message) { Log.Debug("匹配玩家-1"); await ETTask.CompletedTask; } } }
本节最后就是退出房间了,前面退出房间按钮与事件已经加上了。
下一节,我们专门来讲一下前后端如何实现退出房间功能。
为什么专门值得用一节来一个退出房间功能呢?因为需要通过网关通知地图中的gamer,也是检验对Actor的理解,可以明白为什么玩家进入到地图要到网关更新网关上user的ActorID,把gamer的InstanceId赋值给ActorID?