物理引擎的网络同步方案

参考知乎:https://zhuanlan.zhihu.com/p/341447703

外网:https://gafferongames.com/categories/networked-physics/

一个基于C#的3D定点数物理引擎:https://github.com/sam-vdp/bepuphysics1int

 

今天在跟龙哥讨论物理同步的时候,提到一个问题。有物理互动的游戏场景,应该如果进行网络同步?

 

假设有如图的场景,球接近A玩家,A玩家踢了球,而B玩家的网络卡顿了,对A玩家来说,他踢了球,而对B玩家来说,A玩家还没踢到球,

这就导致了逻辑上的不同步。而Unity3D的物理引擎,又是蝴蝶效应的,只要有一点偏差,最终结果会演算成完全不同的样子。

 

这就需要需要解决两个问题:

1.物理引擎必须保持一致性,在不同平台,不同机器,不同时间,对物理引擎输入同样的参数,输出的结果必须一模一样

2.不同玩家的本地物理引擎输入必须完全一致,比如A玩家往前走一步,B玩家里的A玩家也必须在同一时刻往前走一步,不能有任何延迟

 

对于问题1,就是采用定点数的物理引擎,因为浮点数,不同机器精度不同,稍微有一点点的误差,会导致结果演算完全不同,而定点数解决了这个问题。

U3D自身的物理引擎好像不支持修改为定点数,所以一般采用开源的第三方物理引擎自己修改。

问题2,游戏同步方式采用关键帧同步客户端操作逻辑,发送给服务器,服务器再将帧下发给所有客户端,客户端收到帧后再在本地进行物理Update运算出结果

因为服务器下发给所有客户端的帧都是完全一样的,所以客户端不管怎么算,不管延迟与否,算出的结果都是一模一样的。这种方式还解决了一个断线重连问题,

比如A玩家掉线了,重新连上服务器,服务器只需要把这场战斗为止的所有帧都下发,客户端在本地进行快速演算,直到当前帧即可。也能实现游戏的回放效果。

 

参考:火箭联盟的全预测方案

最终我们的项目采用了上面的服务器模拟+客户端插值渲染的方案,不过找到了一些别的资料,在此也分享出来。首先是GDC2018上火箭联盟做的演讲:

  • 火箭联盟是一个以多人载具踢球为核心玩法的游戏,因此物理同步自然是他们要攻破的关键技术问题。
  • 采用了开源的Bullet物理引擎,这样可以自己修改和定制整个流程,而不像Unity中的PhysX是个黑箱。
  • 同步方案上,采用了类似守望先锋的关键帧同步方案,客户端和服务端各自运行物理引擎,客户端不等待服务器数据而是一路向前运行。
  • 客户端维护一个输入缓冲区,保存过去一段时间的每帧的输入数据。待收到服务器数据包后,按照帧号与缓冲区中对应的本地数据进行对比,判断本地在该帧的计算是否正确
  • 如果对比失败,说明预测失败,客户端状态回滚到收到数据包的帧号,应用服务器数据,然后连续运行多次物理引擎仿真,直到追到当前时间,完成一次矫正
  • 物理仿真部分,可以单独拿一个新引擎专门做需要同步物体的仿真,融入现有项目不会太难

这种方案的效果也是非常不错的,付出的代价仅仅是在预测错误时需要在一帧内回滚并消耗CPU连续运行多次仿真,对于PC/主机游戏完全可以接受。不过使用该方案也意味着需要重新部署一套支持确定性仿真的物理引擎,工程量上相对会大一些。

posted @ 2022-08-18 11:29  JeasonBoy  阅读(963)  评论(0编辑  收藏  举报