前言:从4月份至5月份学习了一下unity 目的:为了能够看懂客户端代码最好能够自己写一份属于自己的游戏。
第一次写这类型的代码 也是第一次用unity引擎 写游戏 目前完成了 服务器的设计 当前坦克大战的移动(还存在玩家位置不对的问题)
一张简单的图片概括了 设计思路
简单概括一下 就是客户端做出行为操作 不直接修改行为 而是等待服务器的返回 在updata 脚本里 展示出来
服务器这边代码设计:
一旦有两个 以上的玩家那么就开始分配房间 这一块位置使用的是协程创建协程 分配房间
public Void run() throws SuspendExecution, InterruptedException {
Logger.MLOG.info("#######room:[" + roomId + "]tick start########");
do {
moves.swap();
Queue<PersonMove.CSPlayerMove> dealQueue = moves.first();
while (!dealQueue.isEmpty()) {
PersonMove.CSPlayerMove msg = dealQueue.poll();
if (null == msg) {
break;
}
sc.setPlayerId(msg.getPlayerId());
sc.setMove(msg.getMove());
long sTime = System.currentTimeMillis(); //服务器的时间
sc.getMove().toBuilder().setStime(sTime);
byte[] bytes = sc.build().toByteArray();
Protocal protocal = new Protocal(SCUDP, bytes.length, 0, bytes);
for (Player player : this.players) {
protocal.setPid(player.getPlayerId());
Global.serverChannel.writeAndFlush(protocal);
}
Logger.MLOG.info("msg" + msg + "发送成功");
}
Strand.sleep(40);
} while (true);
}
对于每个client 不停的进行广播 (其实可以进行优化 可以节省一些网络带宽资源 )
帧同步设计思路:
对于打过那种 Xbox 机顶盒的人来说 可以理解手柄 和 显示器是 客户端
机顶盒是服务器 手柄接收到多个玩家操作 然后消息发送至机顶盒 然后再同步到屏幕
客户端的设计:
结构设计
结构分析 GameBegain 是入口函数
CallBack 是处理消息的回调
net层处理消息接收
player 层处理tank 数据
ui 层处理 ui 的消息
创建一个空对象:
挂上脚本GameBegain里初始化 MainManager 在awake 方法里初始化
private void Awake()
{
MainManager mainManager =MainManager.Instance;
MainManager.Instance.State = (int)State.begain;
mainManager.UiMananger=new UIMananger();
mainManager.NetManager=new NetManager("192.168.1.9",12306,"192.168.1.9",12310);
mainManager.PlayerManager=new PlayerManager(new Dictionary<long, Player>());
mainManager.CallBack =new CallBack();
}
创建一个消息队列 放入Tank 的脚本里
当玩家有消息就会往消息队列里存放数据 玩家每次操作的代码
void Update()
{
//调用方法
long playerId = MainManager.Instance.PlayerManager.PlayerId;
float horizontal = Input.GetAxisRaw("Horizontal" + id);
float vertical = Input.GetAxisRaw("Vertical" + id);
if (id == playerId)
{
CSPlayerMove csPlayerMove = new CSPlayerMove();
csPlayerMove.PlayerId = id;
csPlayerMove.Move = new MoveInfo();
csPlayerMove.Move.Ctime = 0;
csPlayerMove.Move.Dir = vertical;
csPlayerMove.Move.Spinning = horizontal;
csPlayerMove.Move.Fire = "";
csPlayerMove.Move.Stime = 0;
byte[] bytes = csPlayerMove.ToByteArray();
Protocol protocol = new Protocol((int) CodeNet.CSPlayerMove, bytes.Length, playerId, bytes);
MainManager.Instance.NetManager.UdpManager.write(protocol);
}
//占时效果的代码
int i = 0;
while (!_SCPlayerQueue.IsEmpty)
{
SCPlayerMove playerMove;
_SCPlayerQueue.TryDequeue(out playerMove);
long playerid = playerMove.PlayerId;
float horizontalc = playerMove.Move.Spinning;
float verticalc = playerMove.Move.Spinning;
if (playerid == id)
{
rig.velocity = transform.forward * verticalc * speed;
if (verticalc > 0)
rig.angularVelocity = transform.up * horizontalc * speed;
else
rig.angularVelocity = transform.up * -horizontalc * speed;
}
//最多一次处理20次消息
if (i == 20) {
Debug.Log("当前服务器消息过多");
break;
}
i++;
}
//Debug.Log(t);
//TanksMove();
//TanksAttack();
}
当前问题 可能由于时间的问题或者分辨率的问题导致 数据有微弱的不同步?
解决方法待定