简介
客户端,相同的状态、相同的输入、相同的计算方式=相同的下一帧状态
服务器,以固定间隔整理所有的客户端输入,整理成一个输入帧,通过网络传输给所有的客户端
需要实现的功能
可靠的UDP
KCP
数据的同步
客户端向服务器
- 在非回放的状态下,Update中,将当前的输入(horizontal、vertical、fire1、mouseDown、useSkill)保存到静态变量(GameManager.CurGameInput)中
- GameManager 中 Update 调用 SendInput ,将当前帧和 curGameInput 发送给服务器
- 接收到服务器发送来的数据,GameManager.PushFrameInput(msg.input) ,将帧和操作数据存入本地(frame 中)
- Update 中,根据 frame 中拿到当前帧的操作,并赋予给 inputAgent ,inputAgent 根据 数据进行位置的移动、角度的旋转
服务器向客户端
- 接受客户端发送来的数据,并在等待间隔后,转发给其他客户端
确定性的数学、物理运算库
存在的问题
- 十进制浮点数无法精准转换为二进制
- 浮点数运算对位
- 随机数不一致
思路
通过扩大倍数,把小鼠部分按照特定的精度变成整数,后续都基于整数来进行运算
物理引擎使用定点数计算,最后虽然将定点数转换为 Unity Transform 的相关浮点数显示物体位置,但是最终在决定物理碰撞、游戏事件、物理移动中都是定点数化后的整数运算,做到物理引擎迭代的确定性,不同机器上跑物理引擎模拟,结果一致,在乘法和除法时容易溢出,可以考虑用两个int来存储值,一个存整数,一个存小数
unity-deterministic-physics 方案
unity-deterministic-physics
Unity DOTS物理版本0.6.0-preview.3的修改版本,它支持使用软浮点的跨平台确定性物理模拟。
数学库、重构的碰撞体之类的没看懂,用法大概是这样,先用着有空再深挖
修改速度
1 |
|
修改阻尼
1 | EntityManager.SetComponentData(entity, new PhysicsDamping() |
运算
加减乘除
1 | # 定点数的位数 |
固定的执行顺序
对于协程等不确定性的方式不能再使用
使用自定义的协程
C#实现类似Unity的协程 - 喊我小怪兽啊的文章 - 知乎
解决方案
- 取整计算法
- 容许小概率误差
- 逻辑表现分离,(表现层可以使用浮点数)
断线重连
通过追帧的方式重新演算到当前帧的游戏状态
比赛回放
服务器记录关键帧
下发客户端进行重放
开发时记录在本地
数据在游戏结束时,序列化成字节,自定义的数据类型需要实现相关序列化和反序列化操作
回放时,读取字节反序列化成原先数据
反作弊
- 重演
- 仲裁