物理系统服务器同步,浅谈物理引擎的网络同步方案!

0x00 前言

本期文章的写作动机是最近碰到的一个问题:在一款在线对战FPS游戏中添加一个多人一起踢球的模式。本以为这个问题解决起来很简单,稍微研究了一会才发现坑还不小。最终花费了好一段时间才初步做出了还不错的效果,于是决定写这篇文章记录一下,抛砖引玉,供大家参考。

0x01 问题描述

我们要实现的效果可以抽象如下:一个场景中存在一个球形刚体(RigidBody)和多个在线玩家,每个玩家都能触碰到球体,并对球施加作用力。由于涉及核心玩法,必须保证每个玩家看到的球体位置与朝向(即Unity中的Transform)同步。

0x02 状态同步初探

说起网络同步,自然会想起经典的各种帧同步与状态同步。

我们先来说状态同步,状态同步的思想是客户端将输入上传到服务器,由服务器计算出结果,再将状态广播给所有客户端,客户端使用获得的状态在本地更新渲染数据。原始的状态同步可以保证每个客户端上获得的结果都是相同的,这能够满足我们的需求,但也存在一些问题:

服务器为了节省带宽,通常状态同步的频率不会很高(

网络环境不稳定,出现丢包或卡顿时,物体的移动会不连续

输入延迟较大,玩家的操作需要等待一个来回才会反映到屏幕上

879837.html

左:客户端 右:服务端 同步频率:每秒10次

其中1可以通过内插值解决,2适用于外插值,3的经典解决方法则是客户端预测+状态矫正。

0x03 内插值(Interpolation)平滑

在收到的两个数据包间通过线性插值插入过渡数据,可以有效平滑物体移动的视觉效果。具体情况如下:

仅需要同步位置(12字节)和旋转(16字节)数据

不立刻应用收到的状态数据,而是多等待一个数据包

根据时间差在过去的两个状态数据间线性插值

对于四元数表示的旋转数据,使用球面插值(Slerp)而不是普通插值(Lerp)

客户端操作 -> 服务器计算 -> 回传状态之后才会开始运动,引入2倍ping值的延迟

879837.html

左:客户端 右:服务端 同步频率:每秒10次 线性内插

对于高速反弹等大幅改变运动状态的情况的模拟会出现一些问题

879837.html

一次快速折返被忽略了

表现效果与通信频率强相关,频率越高效果越高,但也会消耗很多网络带宽

如果出现网络波动连续丢包或者间隔太久,会停在半空中

可以根据收包间隔时间在内插和外插间切换,太久没收到新包,则用外插继续模拟

0x04 外插值(Extrapolation)推测

使用内插值同步时

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值