任务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界面,后面节会有更完整的记得替换。

LandRoom0.zip (2.28KB)

\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?

 

posted @ 2023-02-07 21:51  Domefy  阅读(52)  评论(0编辑  收藏  举报