任务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,用来显示坐到这个位置的玩家的进入房间顺序的索引号,你能自己实现吗?