任务27:前端-进入房间的顺序与座位的判定

上图是座位编号

首先是进房间循序与坐位的规则:

  • 每个人在自己的客户端看,都坐在1号位
  • 三个人坐一圈,我们要做到后进房间的那一个坐在前一个进来的人的右手边

我们定进房间的顺序 : 0,1,2,这也就是遍历服务端传来的三个玩家数据的索引号

定每一个客户端的本地玩家为“我”:

  • 如果我索引号是0,那索引号为1玩家坐右边
  • 如果我索引号是1,那索引号为2玩家坐右边
  • 如果我索引号是2,那索引号为0玩家坐右边

用点数学知识看看下面的结果是不是对上了上面的要求:

  • (0+1)% 3 = 1
  • (1+1)% 3 = 2
  • (2+1)% 3 = 0

我数学也不好,都是硬着头皮学,积少成多!!!

模除(%):大家百度找资料自学,了解下 a>b和a<b的情况下,a%b的结果是什么

//localIndex是本地玩家进房索引号
//AddGamer第二个参数是座位号
for (int i = 0; i < message.Gamers.Count; i++)
{
    // localIndex + 1 指本好玩家后进入的下一个玩家
    // 如果localIndex为0: (localIndex + 1) % 3=1 i为1时的玩家放在2号位
    // 如果localIndex为1: (localIndex+ 1) % 3=2 i为2时的玩家放在2号位
    // 如果localIndex为2: (localIndex+ 1) % 3=0 i为0时的玩家放在2号位
    // 不论本地玩家是第几个进入房间,都放在1号位(下边)
    if ((localIndex + 1) % 3 == i)
    {
        //玩家在本地玩家右边2号位
        landRoomComponent.AddGamer(gamer, 2);
    }
    else
    {
        //玩家在本地玩家左边0号位
        landRoomComponent.AddGamer(gamer, 0);
    } 
}

通过上面的分析,很明显,前面那节是直接按进房索引号给玩家加的座位号,肯定是不对的,测试时候,也能发现你开几个客户端登录,随便点哪个进出房间几次,显示进房人数有错乱。(出现再进房间的索引号数字对应的座位有人了)。

在前端房间组件添加 LocalGamer

public static Gamer LocalGamer { get;private set; }

房间组件初始方法,直接将本地玩家添加到1号座位

//添加本地玩家
Gamer gamer = ETModel.ComponentFactory.Create<Gamer, long>(GamerComponent.Instance.MyUser.UserID);
AddGamer(gamer, 1);
LocalGamer = gamer;

前端房间组件与收到服务端进入房间玩家数据的Handler完整代码

\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 static Gamer LocalGamer { get;private set; }

        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);

            //添加本地玩家
            Gamer gamer = ETModel.ComponentFactory.Create<Gamer, long>(GamerComponent.Instance.MyUser.UserID);
            AddGamer(gamer, 1);
            LocalGamer = gamer;
        }

        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 Gamer GetGamer(long id)
        {
            int seatIndex = GetGamerSeat(id);
            if (seatIndex >= 0)
            {
                return gamers[seatIndex];
            }

            return null;
        }

        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;
            LocalGamer = null;
            this.seats.Clear();

            for (int i = 0; i < this.gamers.Length; i++)
            {
                if (gamers[i] != null)
                {
                    gamers[i].Dispose();
                    gamers[i] = null;
                }
            }
        }
    }
}

\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; //进入房间取消匹配状态
                uiRoom.GameObject.Get<GameObject>("Ready").SetActive(true);                
            }

            //服务端发过来3个GamerInfo 本地玩家进入房间的顺序
            int localIndex = -1; 
            for (int i = 0; i < message.Gamers.Count; i++)
            {
                if(message.Gamers[i].UserID== LandRoomComponent.LocalGamer.UserID)
                {
                    //得出本地玩家是第几个进入房间,可能是0,1,2
                    localIndex = i; 
                }
            }

            //添加进入房间的玩家,判定座位位置
            for (int i = 0; i < message.Gamers.Count; i++)
            {
                //如果服务端发来了默认空GamerInfo 跳过
                GamerInfo gamerInfo = message.Gamers[i];
                if (gamerInfo.UserID == 0)
                    continue;
                //如果这个ID的玩家不在桌上
                if (landRoomComponent.GetGamer(gamerInfo.UserID) == null)
                {
                    Gamer gamer = ETModel.ComponentFactory.Create<Gamer, long>(gamerInfo.UserID);

                    // localIndex + 1 指本好玩家后进入的下一个玩家
                    // 不论本地玩家是第几个进入房间,都放在1号位(下边)
                    if ((localIndex + 1) % 3 == i)
                    {
                        //玩家在本地玩家右边2号位
                        landRoomComponent.AddGamer(gamer, 2);
                    }
                    else
                    {
                        //玩家在本地玩家左边0号位
                        landRoomComponent.AddGamer(gamer, 0);
                    }
                }  
            }

            await ETTask.CompletedTask;
        }
    }
}

现在玩家都按规则坐到了座位上,随便有玩家进出房间,都可以再次坐到空位上。

如上图,我在三个座位的界面位置,加了三个Text,用来显示坐到这个位置的玩家的进入房间顺序的索引号,你能自己实现吗?

posted @ 2023-02-16 14:34  Domefy  阅读(59)  评论(0编辑  收藏  举报