手游载具物理同步的实现方案

作者:GWB-腾讯独立游戏孵化器
2019-10-12
4 3 1

作者:Ned,腾讯互动娱乐 工程师

载具同步的难点

FPS 游戏里的载具,基本上是随着 BR 玩法一起涌现的,基本上每一个大地图的玩法都少不了载具系统。可能在很多人的印象里,人物移动的网络同步不是一件很复杂的事情,按照 UE3 状态机+走路点的方式来实现,基本上最终结果就是可以接受的。但是载具的网络同步却要复杂的多,见下表:

载具
人物
说明
速度快,max 可达40m/s
速度慢,max 只有3m/s
载具的同步结果在时间轴上的一点点误差,会导致位置差别很大。
运动轨迹通常足光滑曲线
运动轨迹可以足仟意折线
载具对同步步质量要求更高,不自然的运动轨迹会立刻引起玩家的注意,而角色的同步轨迹即使跟原始的轨迹差别很大,只要关键位置差不多,玩家或者 QA 就不容易看出来。
运动本身很复杂:相互之间会互相碰撞互相影响运动状态,例如反弹,翻转等等。
运动本身很简单,很多 FPS 里角色的运动只受场景碰撞的阻挡,基本只有 Y 轴有旋转。
角色的移动其实拥有很多限制,利用这些限制条件可以对同步算法做很多简化,例如 3P 的模拟可以完全忽略其他 3P 和 1P 的影响。载具则没办法做这样的简化,而且 “相互影响运动状态”这一点对同步的精确度有很高的要求。
载具同时受到物理系统的控制
角色只受同步逻辑的控制
载具的同步需要结合物理系统和同步算法。

网络同步的本质

我个人觉得对于客户端来说,网络同步可以类比为一个信号重建的过程,从 remote 端接受到原始信号的一系列离散的“采样数据”,然后试图在本地还原出原始信号,可以从信号采样的角度描述成 sampling -> reconstruction filtering -> resampling 的过程。对于人和载具的移动同步来说,“原始信号"就是连续的运动轨迹。好的同步,就等同于好的信号重建结果。

对于移动同步来说,而它的特殊之处在于:

(1)网络延时和传输速度的不稳定,也就是说得到的采样数据(网络同步包)不是等时间间隔的;

(2)手游对网络传输量有所限制,所以网络同步包的频率不可能太大,也就是说 sampling rate 比较低(注意到 resampling rate 其实是游戏帧率),undersampling 在所难免;

(3)原始信号会有“突变”的情况,例如载具高速撞到墙上马上停止下来;

(4)有实时性要求,本地做信号重建的时候只能拿到历史的有延迟的数据,而对于重建结果来说普通情况下只能允许与原始信号存在几百毫秒的延迟,特殊情况下要求几乎零毫秒的延迟。

同步系统概要

名词说明


(1)载具的权威端称之为 master 或者 1P,它代表着“原始信号”,它的运动状态就是“正确的”那个状态。它的 host 可以是服务器,也可以是操控着这个载具的那个客户端。

(2)模拟端称之为 replica 或者 3P,它就是需要在某个客户端上通过信号重建出来的载具对象。

(3)将用于同步的网络包所包含的数据称为 snapshot,其中包含了物理状态信息,例如状态记录时刻、位置、朝向、速度、加速度、角速度等。如上图中的红色圆形所示。

(4)同步算法中的 Interpolation 和 Extrapolation

Interpolation:基于收到的一组 snapshot,插值求出过去某个时刻 master 的位置。如果采取此策略,replica 的状态一定是跟 master 过去的某个状态接近。

Extrapolation:基于最后一个 snapshot,预测出当前/未来某时刻 master 的位置。因为是预测,所以肯定就会有错的时候,但是如果 master 在发出最后一个 snapshot 之后,一直在做加速度恒定的运动的话,那么推算出来的状态就会跟 master 在目标时刻的状态一致。

可以看到 2 个策略各有好处,interpolation 与过去状态高度相似,但是有延迟。expolation 无延迟,但是可能会出现预测错误。

注:Unity 的 rigidbody 就有一个类似的选项,其实表达的是同一个意思。

(5)Dead Reckoning [2]

中文名叫导航推测算法,它利用现在/过去物体位置及速度推定未来位置方向的航海技术。在移动同步的上下文里,这个技术就是根据历史的 snapshot 去猜测一段时间之后(例如 50ms)master 的位置。猜完之后还需要基于 replica 当前的运动状态,设计一条“真实的”移动轨迹使得一段时间之后能够与推测出来的 master 的移动状态一致。

其实 Unreal 的 rigidbody 同步机制里面,也是包含了 dead reckoning 思想的,我记得对应的函数名叫做 applyRBState()

(6)Physics Simulation Blending 表示将物理计算的结果和同步算法得到的结果进行混合,混合的权重是变化的。从实现的角度来说是在不断修改物理引擎计算出来的结果。


系统概要

* master 向 replica 所在客户端以较低频率(例如 50ms)发送 snapshot,包含当时的时刻和运动状态,这个就是原始信号的采样数据;

* master 在生成 snapshot 的时候,会对一些数据求历史均值,例如加速度,角速度等。这个其实是在做 reconstruction filter,把一些高频分量给去掉;

* 如果当前 1P 和 3P 没有发生碰撞的可能,则:模拟端客户端试图重建出 replica 在过去某时刻的运动状态,也就是基于 snapshot 进行 interpolation;

* 如果当前 1P 和 3P 有发生碰撞的可能,则:客户端基于 dead reckoning 技术确定 replica 在当前时刻的运动状态,也就是基于 snapshot 进行 extrapolation,同时确保 replica 开启了物理模拟,如果 1P 和 3P 发生碰撞,则触发 physic simulation blending,碰撞的瞬间混合权重为1,控制权完全交给物理系统,随着时间的推移,混合权重逐渐降低为 0,最终完全受同步算法控制。

核心技术详细说明

(1)网络同步状态下载具之间真实物理碰撞的实现

为了实现 1P 和 3P 载具的“正确的”碰撞表现,需要解决这3个问题:在碰撞发生之前 replica 的精确同步、碰撞时候的物理模拟、对物理模拟导致的 replica 和 master 的运动状态不一致性的恢复。

设想下面这个 case,载具 A 和 B 面对面地高速行驶,最终发生碰撞。如果在 A 的宿主客户端,B 作为 replica 与它的 master 的位置差别较大的话,那么很可能出现一个情况:在 A 的宿主客户端已经发生了 A 和 B 的碰撞,而此时在 B 的宿主客户端 2 者却还相离几米远。这种不一致性,一般被称作 conflict。要较好的解决 conflict,首先当然要保证 replica 和 master 不一致的状态不能差的太多,那么首先就要确保在 A 和 B 的宿主客户端上发生碰撞的时间和位置是非常接近的。只要 replica 的同步在时间和空间上都足够精确,那么这一点就能保证。我们通过基于 Dead Reckoning 技术的 extrapolation 同步策略来实现较精确同步。第二点,则是在碰撞发生时候让本地的物理引擎去模拟出一个真实的碰撞效果。这一点只要保证碰撞发生前物理模拟是开启状态就可以实现。如果 3P 不是始终开启物理模拟的话,则需要预测碰撞的发生,在可能即将发生碰撞之前,启用物理模拟。因为 snapshot 的网络延时和 extrapolation 的预测本质,几乎可以肯定,本地物理模拟之后,replica 和其 master 的位置是不一致的,因此必定需要第三点,也就是 conflict resolve。这个则是通过 Physics Simulation Blending 技术,来保证碰撞发生后的一小段时间内,replica 的运动状态逐渐趋于与其 master 一致,最终消除不一致性。

(2)Projective Velocity Blending

这是 Dead Reckoning 技术的一种,它是以物体在某个时间段内进行的是均加速直线运动为前提,来进行预测和本地轨迹的计算。算法保证得到的结果会是一条平滑的曲线。参见下面的 2 张图(听起来很复杂,其实用的是初中物理知识)。

在本文所述的同步框架里,Projective Velocity Blending 用来实现 expolation 同步。

(3)Physics Simulation Blending

这个技术理解起来其实很简单。想象 replica 载具存在两条不同的运动轨迹:一个是基于 snapshot 用同步算法计算出来的轨迹,另一个是本地物理模拟出来的轨迹。Physics Simulation Blending 就是将这两条轨迹(包含位置和速度)进行混合,其中混合系数随时间变化。在碰撞发生的一瞬间,系数为 1,replica 的运动完全受物理模拟控制,从而表现出真实的碰撞效果。随着时间的推移,系数逐渐降低为 0,replica 的运动完全受到同步算法控制。

(4)Intepolation 同步策略存在的意义

前面说过,实现真实碰撞表现,必须使用 extrapolation 的同步策略,那么 interpolation 同步策略存在的意义是什么呢?extrapolation 在实际运用中,最大的问题是,因为始终只使用表征 master 的“最新”状态的 snapshot 去做预测,所以抗网络抖动能力,非常的差。网络一不稳定,可能就几百 ms 都收不到 snapshot 了,这种情况下还继续做预测基本上就会误差越来越大,导致网络恢复正常之后的 conflic resolve 没法做得很好。而从另外一个角度来说,如果 1P 和 3P 不会发生碰撞,那么我们是完全可以接受 replica 的本地同步状态具有延迟性的。那么使用 intepolation 策略,配合一个 snapshot buffer,就可以更好的适应网络抖动的情况。具体来说就是假如我们的目标是同步 replica 在 150ms 之前的状态,正常情况下的网络延时是 50ms,snapshot 的发送频率是 50ms。在这种情况下,我们始终是使用倒数第 2 个和倒数第 3 个 snapshot 来做 interpolation。如果网络发生抖动导致最新的 snapshot 包没按时接收到,我们可以使用倒数第 2 个和倒数第 1 个 snapshot 来做 intepolation。如果更长的时间还收不到 snapshot,我们还可以把同步策略切换成 extrapolation。

小结

同步框架非原创,参考了 Watch Dogs 2 团队在 GDC2017 上的一篇分享[1]

在实际应用中,这套同步框架还可以被应用到了其他类型的载具上,包括了四轮车、两轮车、直升机、船、无人机。

最后,非常感谢相关同学与我在一些实现技术细节上毫无保留的探讨,谢谢。

引用

[1] Replicating Chaos: Vehicle Replication in 'Watch Dogs 2'
[2] Defeating Lag With Cubic Splines

本文为用户投稿,不代表 indienova 观点。

近期点赞的会员

 分享这篇文章

GWB-腾讯独立游戏孵化器 

腾讯游戏学堂 · 游戏扶持业务致力于为创意游戏团队提供研发指导、技术支持、资金对接和发行推广等全方位服务,帮助团队打磨游戏品质,打造精品游戏! 

您可能还会对这些文章感兴趣

参与此文章的讨论

  1. weartist 2019-10-18

    五笔输入法打错好多字

您需要登录或者注册后才能发表评论

登录/注册