【状态同步】
1、将所有的操作发送给Server(T1),由Server计算(T2),并返回结果(T3)。
权威服务器架构能够防止很多的作弊,但是直接用这种方法会让游戏的响应变得迟缓。
如果 T1 + T2 + T3 非常大,则游戏体验会非常差。比如,Client_1开了一枪,1000ms 后才收到响应,这个游戏体验非常差。
另外,全球发布的游戏,通信常常是由地球的这一端发送到地球的另一端。光速是300000km/s,而地球半周长是20000km,将花费66.6ms。但这只是最乐观的情况 - 假设数据传播的速度是光速,沿着直线传播,这些通常是不可能的。在真实情况下,数据是由无数个路由经过一系列的跳(在计算机网络里的属于叫做hops)进行传播的,而且大部分的传播速度都达不到光速;路由在传播的时候也会产生一些延迟,因为包必须被打包,检查和分发。假设网络因为什么原因发生阻塞了呢?所以实际 100ms,200ms,500ms的延迟也是有可能的。
所以,我们要做的,就是围绕权威服务器来建立一个系统,能够最小的减少玩家的延迟体验,就像在玩单机游戏一样顺畅。
2、Client-Prediction
客户端预表现来优化响应,需要满足一个前提:If the game world is deterministic enough (that is, given a game state and a set of inputs, the result is completely predictable)。
即给定当前帧状态+当前帧输入,能够100%正确和到下一帧状态。
Client-Prediction 可能会带来 Server Data 覆盖 Client Data 导致的抖动问题。
上图中,正确的表现应该是 10->11->12,因为Server Data慢于Client-Prediction,所以实际表现是 10 -> 11 -> 12 ->11 ->12,产生了抖动。
解决方法是,给每个C->S包加上一个序号,当S->C时,带上最后处理的序号。
上图中,当Client收到#1时,重复所有状态为服务器下发状态,并重新执行#2(进行预表现)。所以实际表现会是 10->11->12->12。
3、Dead Reckoning 算法。
此算法用于状态同步下处理玩家的移动。可以缓解 high latency,并且降低带宽。
核心思想:本地模拟,发现差异过大时上传。
在跑的过程中,玩家A有一个值在不停的记录着其真实坐标和在后台模拟运动的坐标的差值,当差值大于极限误差的时候,则计算出当前的速度S、方向O、速度A、位置,并广播给网络中其他所有节点。其他节点在收到这条消息之后呢,就可以用一些很平滑的移动把路人甲拉扯过去。
此种方法下,依赖客户端模拟计算,玩家A可以任意的走动,当不一致时,上报位置。
参考:https://blog.csdn.net/cubesky/article/details/38754911
4、按固定帧间隔(如100ms)同步。
每帧上报一次位置、方向、速度。通过强制每帧只能改变方向一次,可以保持预测的准确性。此法要求更多的带宽,但是相比 DR,画面显示会更加的精确。客户端播放所有其它人的过去的精确位置,以及播放本地的最新位置,这将导致有100ms时差。
参考:http://www.gabrielgambetta.com/client-side-prediction-live-demo.html