最近老师布置了一个作业,是做一个21点游戏,既可以跟AI玩,也可以进行网络对战。对于网络这块,因为最近接触了LuaFramework,它在通信方面也进行了一层封装,看了一下,觉得还是挺不错的,所以就打算用它来搞。因为客户端和服务器端的工程体积挺大的,所以就不放出来了。其实模仿框架中的例子已经可以做出很多东西了,所以这里就说一下额外的比较关键的东西。
游戏截图:
服务器端:
1.首先我们需要定义一些消息,客户端也要复制一份。
Wait = 3000, //客户端等待 WantEnter = 3001, //客户端请求进入房间 Enter = 3002, //服务器允许进入房间 HadEnter = 3003, //客户端已进入房间 ShowWantCard = 3004,//服务端显示要牌按钮 WantCard = 3005, //服务端允许要牌 Card = 3006, //服务端发牌 NotWantCard = 3007, //客户端不要牌 ShowResult = 3008, //客户端显示结果
2.然后就是匹配的事情,我们需要把玩家都放在同一间房间中。
using SimpleFramework.Common; using SimpleFramework.Message; using SimpleFramework.Utility; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SimpleFramework.MyCode21Game { abstract class Room { protected int number;//房间号 protected int capacity;//房间容量 protected int hadReadyCount;//已经准备好的玩家数 protected List<ClientSession> playerList; public Room(int number, int capacity) { this.number = number; this.capacity = capacity; this.hadReadyCount = 0; this.playerList = new List<ClientSession>(); } public void AddReadyPlayerCount() { hadReadyCount++; if (hadReadyCount == capacity) OnAllReady(); } public void RemoveReadyPlayerCount() { hadReadyCount--; } public void AddPlayer(ClientSession clientSession) { clientSession.roomId = number;//房间ID,或者是地图ID clientSession.roomIndex = playerList.Count;//房间序号,即表明是第几个玩家 playerList.Add(clientSession); if (playerList.Count == capacity) OnFull(); else OnNotFull(); } public void RemovePlayer(ClientSession clientSession) { clientSession.roomId = -1; clientSession.roomIndex = -1; playerList.Remove(clientSession); if (playerList.Count == 0) OnClear(); } public bool IsFull() { if (playerList.Count < capacity) return false; else return true; } public virtual void OnAllReady() { } public virtual void OnFull() { } public virtual void OnNotFull() { } public virtual void OnClear() { } //一般为一局游戏结束后调用 public virtual void Reset() { hadReadyCount = 0; } public virtual void Destroy() { } } }
using SimpleFramework.Common; using SimpleFramework.Message; using SimpleFramework.Utility; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace SimpleFramework.MyCode21Game { class CardRoom : Room { private List<Card> cards; public CardRoom(int number, int capacity) : base(number, capacity) { cards = CardManager.Instance.GetCards(); } public override void OnAllReady() { base.OnAllReady(); Console.WriteLine("所有玩家已经准备好,开始发牌!!!"); foreach (ClientSession client in playerList) { Deal(client); } Thread.Sleep(1500); foreach (ClientSession client in playerList) { Deal(client); } //同时第一个玩家可以要牌 ByteBuffer bb = new ByteBuffer(); bb.WriteByte((byte)ProtocalType.BINARY); SocketUtil.SendMessage(playerList[0], Protocal.ShowWantCard, bb); } public override void OnFull() { base.OnFull(); Console.WriteLine("满人!!!"); foreach (ClientSession cs in playerList) { ByteBuffer newBuffer = new ByteBuffer(); newBuffer.WriteByte((byte)ProtocalType.BINARY); newBuffer.WriteString("匹配成功,房间号是:" + number); newBuffer.WriteInt(cs.roomId);//设置客户端 newBuffer.WriteInt(cs.roomIndex); SocketUtil.SendMessage(cs, Protocal.Enter, newBuffer); } } public override void OnNotFull() { base.OnNotFull(); Console.WriteLine("还没满人!!!"); foreach (ClientSession cs in playerList) { ByteBuffer newBuffer = new ByteBuffer(); newBuffer.WriteByte((byte)ProtocalType.BINARY); newBuffer.WriteString("人数不足,请等待..."); SocketUtil.SendMessage(cs, Protocal.Wait, newBuffer); } } public override void Reset() { base.Reset(); Console.WriteLine("重置房间"); cards = CardManager.Instance.GetCards(); } //抽牌 public void Deal(ClientSession session) { Card card = cards[0]; cards.RemoveAt(0); Console.WriteLine("玩家为:" + session.roomIndex + "牌为:" + card.ToString()); ByteBuffer newBuffer = new ByteBuffer(); newBuffer.WriteByte((byte)ProtocalType.BINARY); newBuffer.WriteInt(session.roomIndex);//第几个玩家 newBuffer.WriteString(card.ToString()); foreach (ClientSession client in playerList) { SocketUtil.SendMessage(client, Protocal.Card, newBuffer); } } //下一位玩家 public void Next(ClientSession session) { ByteBuffer bb = new ByteBuffer(); bb.WriteByte((byte)ProtocalType.BINARY); int nextIndx = session.roomIndex + 1; if (nextIndx < capacity) { SocketUtil.SendMessage(playerList[nextIndx], Protocal.ShowWantCard, bb); } else { foreach (ClientSession client in playerList) { SocketUtil.SendMessage(client, Protocal.ShowResult, bb); } Reset(); } } } }
using SimpleFramework.Common; using SimpleFramework.Message; using SimpleFramework.Utility; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SimpleFramework.MyCode21Game { class RoomManager : CSharpSingletion<RoomManager> { public Dictionary<int, Room> roomDir = new Dictionary<int, Room>();//房间号,房间 private int roomNum = 0;//不要使用字典长度作为key //顺序分配 public int GetDefaultRoomNum() { if (!roomDir.ContainsKey(roomNum)) return roomNum; if (!roomDir[roomNum].IsFull()) return roomNum; roomNum++; return roomNum; } } }
客户端:
1.框架默认的是通过SocketCommand.cs将消息分发到lua中,在lua中写逻辑,这样逻辑随便写也没关系,因为可以通过热更新换掉。而我这里为了加快开发效率,直接在c#中写逻辑,因此就需要修改一下框架,将消息在c#中进行分发。
using UnityEngine; using System.Collections; using System.Collections.Generic; using LuaFramework; public class SocketMessageManager : MonoSingletion<SocketMessageManager> { public delegate void SocketMessage(KeyValuePair<int, ByteBuffer> dir); public event SocketMessage socketMessage; public void Dispatch(KeyValuePair<int, ByteBuffer> dir) { Debug.Log(dir.Key.ToString()); if (socketMessage != null) socketMessage(dir); } }
void Update() { if (sEvents.Count > 0) { while (sEvents.Count > 0) { KeyValuePair<int, ByteBuffer> _event = sEvents.Dequeue(); //facade.SendMessageCommand(NotiConst.DISPATCH_MESSAGE, _event); SocketMessageManager.Instance.Dispatch(_event); } } }
public void HandleSockMessage(KeyValuePair<int, ByteBuffer> dir) { switch (dir.Key) { case Protocal.ShowWantCard: if (CardManager.Instance.CountCard(Game21Manager.Instance.player) < 21) { ShowButtonWantCardAndNotWantCard(); } break; case Protocal.Card: dir.Value.ReadByte(); int roomIndex = dir.Value.ReadInt(); string card = dir.Value.ReadString(); if (roomIndex == Game21Manager.Instance.roomIndex)//如果是自己的牌 { GetCard(card); } else { CardManager.Instance.GetCard(banker, new Card(card)); } break; case Protocal.ShowResult: ShowCard(); break; default: break; } }