帧同步
一句话概括:服务器只做转发,伤害,位置等计算由所有的客户端(同一个版本下)独立计算,如果代码没有错,那么计算结果将是一致的。
优点:减轻服务器压力,精确度高。
缺点:重连时间长,容易不同步(计算结果不一致),不能用浮点数计算(浮点数经过网络传输后可能就不对了,甚至是同一台机器经过几次赋值浮点数就不一样了)。
某乎大佬的解释:
在游戏的每个帧同步用户事件,经服务器广播之后,在每个客户端模拟状态变更。由于只同步用户事件,所以网络传输的数据块比较小,同步又比较及时,非常适合格斗游戏这种需要做精确模拟的游戏。而且由于只同步事件而非状态,所以网络传输的数据和游戏里的对象数量无关,比较适合于包含较多游戏单位的游戏,比如及时策略游戏。对于单个用户,由于网络传输往往不稳定,往往影响模拟的稳定,从而导致渲染时的跳动(jitter)。为了处理这个问题,往往会引入事件的buffer来平滑网络传输。但是这又影响了模拟的及时性。而且由于不存在状态,所以对于需要断线重连时,往往由于客户端需要重新完成之前所有模拟,所以重连时间较长。对于多个用户,由于为了保证所有人同步,往往需要等待最慢的客户端,从而使整个游戏非常容易受到单个用户的网络延迟的影响。而且只同步事件,往往比较难以防范欺诈。当然最麻烦的问题还是要保证客户端模拟的一致性,于是这个模式有时候又叫 Deterministic Lockstep。包括使用一样的随机种子所伪随机运算,不使用浮点数运算等。通常使用这种策略的都是局域网游戏。帝国时代,王者荣耀,还有知名的DOOM,都用的是这种策略。
快照同步
这个我不是很清楚。
某乎大佬解释:
这是在C/S模式中最简单的同步策略。客户端将事件发送给服务端,服务端完成模拟之后定期将所有状态的快照同步给客户端。由于所有的模拟都在服务端,这种策略最容易用于防止欺骗。而且在这种模式下,所有的客户端都可以看做是服务器状态的一个 terminal,所以实现起来也最容易。最好的一方面就是不受到单个用户的网络抖动的影响,但是网络比较快的用户往往就有比较大的优势。由于要同步所有游戏对象的状态,所以网络传输的数据包往往较大,无法实现比较实时的同步。为了应对数据包过大,往往会要求使用一些压缩的编码方法,比如 Delta Encoding。为了应对不及时,就需要对snapshot进行 Interpolation 和 Extrapolation。差值时为了保证游戏中运动平滑,会使用比较复杂的差值算法,但是往往还是往往容易显得不自然。通常使用这种策略的都是游戏状态比较小,对实时性要求不高的游戏。不少基于HTTP协议的游戏,都是采用这种策略。
状态同步
这个是最容易想到也最难实现的策略。客户端和服务端都模拟状态变更,客户端将事件发送给服务器后,在本地预测状态变更。服务器受到状态后,在服务器上也做同样的模拟,然后将变化的状态传回给客户端。对于没有变化的对象,客户端保持原有状态(运动或者静止),对于变化了的对象,客户端以服务器的返回为准。由于服务器的状态返回往往有延迟,所以客户端会在收到新状态之后,重放同步点之后的事件。好处就是,无论是传递的数据内容、大小,还是同步的频率都是可以调整的,所以可以在模拟的精细和模拟的效率之间找到一个较好的平衡,而且由于在客户端也进行模拟,往往用户收到的反馈也更及时,体验也更好。不过由于要将服务器端和客户端运行一样的模拟,所以也存在双端同步的问题。最后,其实以上协议,只是让玩家的状态实现同步。而影响实时性的最大关键在于网络,所以为了接近实时,需要尽量降低网络延迟,包括降低传输数据量,使用UDP来避免TCP的重传问题等。此外为了而让玩家的动作感觉起来像是实时同步,往往要靠本地的Extrapolation。
各种同步学习笔记
![](https://img-home.csdnimg.cn/images/20240711042549.png)