在实际开发中,比方说我与服务器约定每秒20帧,服务器以每0.05S是的时间广播消息, 客户端以同样的帧进行同步处理, 理论上如果没有延时,整个位移是非常平滑的。但是,如果网络不好, 客户端接收服务器的帧数据,都是大于0.05秒的,比方说,网络不好,客户端收到服务器的每帧消息都是0.09S, 这个时候,客户端以每0.05秒的时间从帧缓存容器中去拿数据,就会出现拿不到的情况,就算是在刚开始移动的时候,先压几帧,但是因为网络不好,这几帧很快就会消耗完,这时候,在视图层就会发现,人物走动是一卡一卡的,这种情况该如何处理呢。
我做了一个办法,就是当从帧缓存容器中拿不到数据的时候,判断最后一帧是不是走动数据,如果是走动数据,就以这个数据的方向走几帧,等拿到数据的时候,再进行校准位置,,但是这种效果非常差,因为每一帧移动到哪个位置都是可以算出来的,当预先走几帧,等收到服务器的消息进行校准的时候,角色会先移动到正确的位置,然后在根据后面的服务器广播的指令进行移动,做出来和卡顿的效果差不多,角色总是突然回头走然后再根据正确的方向走!
如大家所说,“这个问题无解,只能优化体验”,那我们就讨论“优化”吧!
1.首先,得定个基线,这个基线包含:在什么网络程度用户体验流畅,什么程度上用于体验可以接收,什么程度上保持逻辑一致和稳定就够了。具体基线和网络和游戏设定有关系,建议在纸上先论证清楚。我们这里主要讨论网络,可以去找找网络延时得分布,我们通常得建议是,网络延时,100毫秒以内,用户体验流畅,100-200毫秒,用户体验可以接收,200-400毫秒,勉强可玩,400毫秒以上,保证稳定和一致性的前提下,尽量能玩。200毫秒能覆盖很大部分的玩家了,有了这个基线,项目组就可以进行更好的游戏设定,如果不考虑基线,这个问题真的无解。
2.每秒20帧,如果位置移动按照这个频率采样,看起来会不够流畅,一般的做法,是表现层做平滑,将时间片拆成更小的粒度,使得位置采样更密集,这样移动看起来更平滑。
3.表现层预测,如题主所说的,保持运动的惯性,第2点说了,时间片的粒度更小,那么误差的范围可能更小,设定一个容差范围,通过表现层的平滑将误差逐步修正,允许表现层位置和逻辑层位置在一定范围内不一致,这是关键,而“这个范围”就是用来“包容”网络延迟的。
4.绝对的网络延迟导致的主要是用户输入的延迟,位移的抖动更多的是网络抖动造成的,题主可以加如一些抗抖动的技巧,原理上是把时间轴上分布不均匀的信号,尽量均匀化,可以搜下jitterbuffe!

  

  大概的意思就是随时修复,太大就跳!

  我们也用的帧同步也面临过这个问题,最终从几个方面有了大幅改进。1.分析延迟是否有逻辑问题,比如我们一开始有部分延迟是因为逻辑在FixedUpdate里执行,因为更新顺序问题导致客户端相应操作慢一帧,修改Unity源码解决之后帧率有较大提升。2.网络层面极致优化,使用UDP并且使用非可靠UDP,通过冗余包的方式降低延迟冗余包的个数依赖MTU并不固定,当然前提是每个帧操作的包也要极致优化。此外客户上行可以允许丢包,客户端操作的发送立即执行频率比逻辑帧高,使用多线程。3.最后还可以进行一些预表现。比较好的做法逻辑层和变现层是分离的,客户端表现层可以预表现一定的位移,然后通过航位预测算法逐渐差值到逻辑层的位置,这样就不会出现突然回头再网正确方向总的情况了。对于帧同步来说解决平滑位移的基础还是网络层的极致优化,然后再考虑平滑差值和预表现。

  首先如果是移动网络的话,建议用UDP通信而不是TCP通信。
如果对实时性要求不是非常高的游戏,可以采用可靠UDP在客户端延迟播放帧,延迟的时间周期可以通过UDP包丢失后重传机制进行补齐后再继续播放帧
如果对实时性要求非常高的游戏,如上通过ACK确认UDP丢包后再重传机制可能时间上来不及了,这时候直接采用双发重复发送UDP包的机制可能更好。双发会带来网络流量翻倍上升,这时候可以通过统计识别出来哪些玩家的网络好哪些玩家的网络不好,对于网络好的玩家使用正常的单发UDP包,对于网络不好的玩家才使用双发UDP包。