帧同步基本原理

帧率设定为 40 帧,每帧间隔 25ms。服务端基于 Windows Socket 的 TCP 协议,客户端使用 Unity。

服务端通过轮询方式接收客户端消息。若在一帧时间内未收到某客户端的消息,则默认该帧为空帧,并将其广播给所有客户端。客户端发出的帧数据以服务端实际收到的帧序号为准。例如,客户端在第 25 帧发出了帧数据,但服务端在第 30 帧才收到,那么第 25 到第 29 帧,服务器均视该客户端为空操作。

服务端房间主循环

下图展示了一个房间的主循环逻辑:

RecvTickSendTick 分别负责轮询接收和发送客户端消息。由于每个房间设计上只使用单独一个线程,主线程在接受到连接请求后需要对房间加锁,再动态添加玩家。


客户端帧序列处理

客户端只有在收到正确的帧序列信息后才开始逻辑运算,逻辑运算不影响画面的 Update。服务端会发送一个时间戳作为随机数种子。

客户端帧处理遵循以下规则:

  1. 若收到第 25 帧和第 27 帧的数据,处理完第 25 帧后会持续轮询等待第 26 帧到来,才会继续计算第 27 帧。
  2. 若收到重复帧,以已存在的帧数据为准进行计算(客户端重连时,服务端可能会多发送几帧)。
  3. 当玩家加入已进行中的对战,服务器会一次性发送之前所有帧数据,客户端将一次性计算至当前最新帧,此时收到的数据很可能同时触发第 1、2 条规则。

为了保证玩家体验,当连续计算达到 80 帧时,会主动放弃本次计算机会,让 UI 更新一次,显示加载进度。

加载效果如下:

断线重连与房间管理

当玩家断开连接并发起重连时,客户端会携带 Room ID 和自身 ID 重新动态加入上一局游戏,处理方式与规则 3 相同。

服务器策略:持续等待客户端连接,并将其加入满足条件的上一个房间;若上一个房间不允许加入,则创建新房间。