# 前言
之前没研究帧同步,这是我前端时间没上班时边玩边搞做的 Demo 研究成果,总共时间一周(实际2-3天),发布的目的也很简单,打破技术垄断,才能诞生更高端的技术成果。而且就算我没发这篇帖子,迟早也会有相同想法的人发布
# 帧同步
这里我不会说太多,网上也有很多教程,我并没有看太多,只是说说自己的看法
1. 了解帧同步
同步操作而不是状态
帧同步简单的说就是同步玩家的操作而不是状态,比如向服务器发送我按下了什么按键就是传递操作,而发送位置数据就是传递状态。
保证同步一致性
帧同步为什么叫帧同步?因为客户端的游戏进程是根据服务器下发的帧数据推进的,每下发一帧则更新一次游戏,确保了所有客户端展示一致
-
问题:服务器需要发送什么数据给客户端?
答案:当前帧下标,所有玩家的操作数据 -
问题:客户端怎么发送操作数据到服务器?
答案:统计当前帧产生的操作,在下一帧统一发送给服务器,在这里客户端需要筛除无用数据,例如只能执行一次的两个相同操作数据。
重连
帧同步需要服务器缓存从游戏开始到当前为止玩家的操作数据,然后在玩家重连时将所有数据发给客户端,客户端则根据帧数据同步游戏直到和当前帧一致,才算重连成功,所以这也是为什么帧同步游戏重连时间长的原因
相信到这里你已经简单了解了帧同步的原理。那么我们继续进行了解怎么做物理帧同步。
2. 帧同步的优化
预测和回滚
预测:就是按照你的游戏逻辑预测玩家的操作,例如 lol 网络卡时候的惯性移动就是预测
回滚:在预测之前记录当前数据,接收到服务器帧数据后,如果结果和预测结果一致则不回滚,不一致则用记录数据回滚到之前的状态
# 物理帧同步
1. 已知规则
- JavaScript 的浮点基础运算在各个平台是一致的(遵守ECMAScript 2015 (ES6))
https://stackoverflow.com/questions/42181795/is-ieee-754-2008-deterministic
- JavaScript 三角函数是提供了建议实现,实际只需要达到近似值即可满足要求,所以在各个平台可能并不一致
https://262.ecma-international.org/6.0/#sec-function-properties-of-the-math-object
https://forum.cocos.org/t/topic/155837
- WASM 的浮点运算是确定性的
https://forum.cocos.org/t/topic/155837/4
- C++ 的浮点数运算需要确保相同的架构和编译器才能确保一致
https://stackoverflow.com/questions/20963419/cross-platform-floating-point-consistency
2. 帧同步
-
手动物理引擎步进:非手动控制步进会导致物理世界运算(step)次数不一致,导致最终的结果差异
设置自动步进:cc.PhysicsSystem2D.instance.autoSimulation = false;
cc.PhysicsSystem2D.instance.enable = false
需要在脚本加载时被执行,防止物理世界自动执行 step -
预测:使用渲染预测,物理世界依旧暂停,只控制渲染移动。回滚时只需要控制渲染位置即可
-
确保物理世界数据的一致性:在 Cocos 的物理引擎实现中,通常只是做一个接口同步物理和渲染,所以物理引擎内还存在刚体的坐标与旋转数据。为了确保多端的物理世界数据一致,需要确保节点的 世界坐标 和 世界旋转 在多端一致,具体可以自行查看物理引擎的 syncSceneToPhysics 实现。
-
重置物理引擎实例:个人推测也是因为设备间物理世界运算次数不一致导致的。解决方式为要么根据服务器指令结束物理循环(运算相同次数),要么重置物理引擎实例
https://forum.cocos.org/t/topic/136991?u=1226085293
3. Web 帧同步
-
修改三角函数:在我个人测试中,safari 和 chrome 的表现结果一致,但由于三角函数的不确定性,建议还是修改三角函数为确定性实现。并不一定需要使用查表法(提前存储结果),由于 JS 四则运算的一致性,我们可以使用 JS 自身实现,这里推荐使用 stdlib 库。
-
检查物理引擎源码:在部分物理引擎中,为了更快的速度,有些会使用 let xxx = Math.cos 这种方式调用数学库实现。所以需要检测物理引擎源码,例如 box2d 就是这样
4. 原生/多端 帧同步
-
使用 js 或者 wasm 类型的物理引擎,C++ 需要保证相同架构和编译器,才能防止语言带来的浮点数差异
-
使用定点数物理引擎,例如 repper.js
https://forum.cocos.org/t/topic/133618/44
如果想要确定 Web 和 原生使用的物理引擎是否为同一语言,可以自行查看引擎原生代码是否包含这个物理引擎,例如 Physx 就有 C++ 版本
引擎 Web 代码路径:resources\resources\3d\engine\cocos
引擎原生代码路径:resources\resources\3d\engine\native\cocos
示例项目
只做了简单的同步,没做追帧、预测、回滚
服务端 Nodejs
https://github.com/1226085293/PhysicalFrameSynchronization
测试环境:Safari + Windows Chrome
参考资料
- 理解确定性:https://shaderfun.com/2020/10/25/understanding-determinism-part-1-intro-and-floating-points/
# 结语
对于有物理同步需求的回合制游戏来说,你甚至不需要帧同步,只需要做到上面说的要求,一样可以做到物理同步,例如 台球
好了,快去做出你心仪的游戏吧,不必为技术困扰,另外加入我技术群的小伙伴可以提前知道我发布的最新技术成果哦。
🐧企鹅2群:348096019
🐧企鹅群:200351945