先简单描述下本篇记录的是什么. 起因是服务器这段时间在查流量,需要严格控制乃至减少现在数据包的 大小/频率。
目前服务器的逻辑大概在30hz的频率刷新当前逻辑块,客户端并未走单独的逻辑刷新层。故现在客户端并未按照帧去判定当前是否同步,而是走固定的刷新周期。
250ms为一个刷新周期,触发当前同步的判定;

先列一下几种位置同步的【条件】:

1
2
角度是否变更
位置是否变更

在固定的周期内会检测一次两个条件是否超出一定的阀值,如果超过定量则在该周期内同步一次。服务器则根据当前同步的角度预测计算帧当前角色可能的位置。

如果是这种做法,当前移动速度为6m/s :

1
2
3
4
客户端刷新周期250ms,延迟为200ms,服务器得到当位置的最大误差为: (0.25s + 0.2s) * 6m = 2.7m   每秒4个包
客户端刷新周期100ms,延迟为200ms,服务器得到当位置的最大误差为: (0.1s + 0.2s) * 6m = 1.8m 每秒10个包
客户端刷新周期50ms,延迟为200ms,服务器得到当位置的最大误差为: (0.05s + 0.2s) * 6m = 1.5m 每秒20个包
...

以此类推,稍微优化一下也用不了那么多包,如果【条件】没有变更的话是不需要持续在周期内同步。也就变成了每帧判定【条件】是否变更,如果没有变更则无需同步,
否则走默认的周期检测,检测周期也就可以改为1s同步一次当前位置。

条件的改变频率

在此基础上可以知道延迟固定的最大误差为 0.2s * 6m = 1.2m ,那么现在基于此应该去尽量少的发送数据包,也尽量少降低误差。
如果【条件】改变的频繁会大幅增加发包的数量,甚至可能每帧都产生一个包。如果玩家在原地绕圈的时候.
此时增加【条件】的冗余可以减少当前发包的数量,如 增加 角度/距离 变更的判定范围。
实际上这样做的效果并不好,原因是【条件】太容易满足。

基于误差累计替换【条件】(航位推算法DR)

前面有说到服务器预测当前物体,在计算帧的坐标是基于 运动朝向 + 物体坐标

那么在我们的检测代码中可以做两次计算:

先预测服务器得到的当前物体位置 : 上次同步的坐标 + 运动方向 * 同步结束后累计的时间
计算当前物体实际距离与 预测服务器得到的当前物体位置 之间的距离

如果当前位置与服务器预测的位置误差控制在一定的范围内则不需要同步反之立即同步一次;

这样的好处是误差可以控制在一定的范围内并且尽量的少发送同步包;比如误差控制在0.1m范围,如果发送的包超量再适当的增加此范围。

基于时间戳修正

这两天还在调试 尽量取一个比较折中的方案,如果实在达不到预期再考虑 双端同步时间种 基于此各自做运动状态的计算。

更新:撞墙如何处理

撞墙后通过代码使人物转向,不要降低运动速度即可。

参考文档

开发笔记(12) : 位置同步策略
网络游戏的对时以及同步问题-云风的 BLOG
状态更新及航位预测法