游戏开发者笔记--帧同步和状态同步

帧同步和状态同步从技术上来说有什么区别

  • 状态同步

    • 状态同步是大型网游普遍会采用的一种同步技术,它特点是客户端会向服务器发送一些指令,比如在角色扮演类中从游戏的NPC那里买一些物品时,客户端会向服务器发送一个指令,指令中包括玩家ID、购买商品的ID号、商贩NPC的ID号,将这些信息传到服务器后,服务器会计算玩家的金钱是否足够,当前所处位置是否在NPC身边、NPC是否有这个物品等等

    • 服务器会做很多校验,校验完以后才能确定玩家是否能购买物品,如果不能买服务器就会给客户端下发一个交易失败的指令,可以购买服务器则会下发玩家在购买完商品以后,背包里面增加了哪些东西,或者减少了哪些东西的消息

    • 状态同步的特点就是状态同步发送的是一些操作,接收的是一些状态,这些状态数据可能会很大,所以在同步时所要同步的数据量也会比较大,状态同步的的好处就是安全性比较好,反作弊能力比较强

  • 帧同步

    • 帧同步的特点可以总结为六个字:发操作、收操作,也就是说客户端发送的是操作,接收的也是操作,服务器在接收到客户端发送的操作后,不会做任何运算,而是以广播的形式将这个操作发送给同一房间里的所有玩家

    • 其他玩家在接收到的操作后就会产生相应的画面表示,比如玩家1发射了一颗子弹,那么在玩家2的客户端上就应该实例化一颗子弹出来,然后让颗子弹以一定的速度朝某一个方向发射,这就是帧同步的一个特点

    • 帧同步将所有运算都放在客户端去做其实有一个非常大的好处,就是它的运算非常简洁因为就像在开发一个客户端游戏一样,服务器不需要做什么太多的工作,如果你是一个优秀的客户端开发者就可以比较轻松的实现一个相对比较完善的帧同部框架

假设要操控一百个游戏单位,帧同步和状态同步操作的区别

状态同步:

发送到服务器:

  • 游戏单位列表(100*4b)

  • 目标地点(8b)

定期同步给每个客户端:

  • 100个游戏单位的ID(100*4b)

  • 100个游戏单位的位置(100*8b)

假设每秒同步一次,到达目标需要五秒:

100*(4b+8b)*5 = 6000b

帧同步:

发送到服务器:

  • 帧号(4b)

  • 游戏单位列表(100*4b)

  • 目标地点(8b)

一次性发送给每个客户端:

  • 帧号(4b)

  • 游戏单位列表(100*4b)

  • 目标地点(8b)

总计4b+100*4b+8b = 412b

通过这样的对比我们就可以看出帧同步比起状态同步的同步量差距在哪了

  • 使用状态同步来控制100个游戏单位移动

    • 如果采用状态同步控制100个游戏单位进行移动就要发送这100个单位的ID号到服务器中,光是发送ID号就要发送掉400个字节

    • 还有这100个单位的目标点也是要占8个字节的,因为要传一个X坐标和一个Z坐标,X坐标四个字节,Z坐标四个字节加起来就是八个字节了,发过去就是408个字节,如果游戏中有多个玩家,就要发多个408个字节过去,状态同步的耗费就在这里

    • 状态同步更耗费的一点在于服务器往客户端同步数据时的开销,因为服务器往客户端同步数据时要定时同步,就算我们服务器的同步频率比较低,那一秒至少也要同步一次,这时假设客户端一秒同步一次,我有100个单位,那么每次同步我都要同步100个游戏单位的ID号也就是400个字节,刚才我们算过了

    • 我还要同步这100个游戏单位走到了什么位置,因为中间会存在一些路径障碍,所以这些玩家的坐标位置在一秒以后都是不一样的,所以还要计算这100个游戏单位一秒以后的位置,那么每一个位置是占8个字节,现在有100个单位,那么一共是多少个字节呢?

    • 一共是1200个字节,这只是一个玩家的开销就已经很恐怖了,那假设我从起点到目标点需要5秒钟,那总共需要同步多少个字节呢?就是6000个字节,这是怎么算的呢?就是100个游戏单位,每个单位的ID号4个字节,坐标位置8个字节,加起来是12个字节,100乘以12就是1200,再乘以五就是6000了

  • 使用帧同步来控制100个游戏单位移动

    • 帧同步是当玩家执行操作时客户端会向服务器发送一个帧号,帧号是什么意思呢?就是当前是在进行第几帧操作,帧同步是定频的(固定数据发送的频率)

    • 游戏单位是400个字节,目标地点是8个字节,就要发送408个字节,这和状态同步差不多,但由于帧同步是直接把操作返回给所有的客户端,让客户端自己计算,所以它的开销就很小

    • 帧同步只要传回这个操作是在第几帧发生的、发生时玩家要移动到什么位置、哪些目标要往这个地点移动,所以它接收的数据是408个字节,发送的数据也是408个字节

  • 可以看出帧同步与状态同步的差异非常大,因为状态同步所同步的是状态数据,而帧同步所同步的只是操作数据,返回的数据量不大,而且帧同步所有的运算压力都在客户端上面,不在服务器上,服务器只要带宽足够大,能够定时中转数据就可以了

再从代码编写来看下两个同步方式的区别:

帧同步 状态同步
服务器代码编写复杂程度 √只负责转发 需要处理大量的逻辑,然后机进行计算转发
客户端代码复杂程度 必须保证每个玩家的客户端计算结果一至(随机数,字典等无法使用,数学和物理稳定性) √根据返回的结果进行客户端的数据更新和画面表现即可
中途加入游戏 需要追帧 √下发数据状态即可
服务器带宽需求 √只传输操作,开销小 每个受控角色都要传状态(每个单位)
客户端游戏体验 √本地运算,反应灵敏,打击感强 延迟相对较高
反作弊 需要服务器和客户端共同参与,难度较大 √服务器权威
离线战斗
  • 服务器代码编写复杂程度

    • 帧同步的服务器代码编写相对来说比较简单,因为帧同步只是转发数据
    • 因为状态同步的大量逻辑运算都是在服务器上进行的,所以如果你不是一个熟练的服务器开发者,你所要面对的第一个问题就是无法在服务器中调用Unity里的那些方便的API,比如计算坐标、计算朝向等等,这些都需要服务器程序员自己实现
  • 客户端代码的编写复杂程度

    • 帧同步

    • 帧同步的客户端代码编写复杂程度比状态同步要复杂的多,帧同步必须要保证每个客户端的计算结果是完全一致的,比如游戏中常用的一些随机数,帧同步必须要保证所有玩家生成的随机数序列是相同的,因为这个原因,在帧同步中字典是不能用的,因为字典是一个无序列表
      • 因为数学的物理运算都会牵涉到一些浮点数,而浮点数是具有不稳定性、不精确性的,所以在帧同步中不能用传统的Unity里提供的那些数学和物理库了,必须自己实现一套

    • 状态同步的逻辑都是在服务器上进行运算,所以就算服务器上有一些浮点数误差也没有关系,只要发给所有客户端的结果是一样的就行了
  • 中途加入游戏

    • 帧同步要中途加入游戏需要追帧,所以一些采用帧同步的网络游戏大多都要一个很明显的特点,就是中途加入一局游戏时都需要等一会儿
    • 因为状态同步是直接下发当前的角色状态,所以它不需要等待
  • 服务器带宽要求

    • 帧同步对服务器带宽要求比较小,因为帧同步只需要传递操作
    • 状态同步因为同步数据量比较大,所以对服务器带宽要求比较高
  • 客户端体验

    • 帧同步的逻辑运算是在本地进行的,所以它的反应更加灵敏,打击感更强
    • 状态同步的延迟相对要高一些
  • 反作弊

    • 帧同步在反作弊上是有点问题的,帧同部需要所有的客户端进行协作来判定玩家作弊,所以比较容易出现一些很变态的外挂

    • 状态同步就算有外挂,也大多是辅助性的外挂,危害性要稍微弱一些
  • 离线战斗

    • 所谓的离线战斗就是不连服务器,也能进行战斗,帧同步很容易就能实现,因为帧同步本身的框架就是基于每一帧数据的,帧同步在进行离线战斗时会在客户端做一个虚拟的服务器,这个服务器会把客户端发送的数据发回给自己
    • 状态同步要做离线战斗就不太容易

 看到这里我们就可以总结帧同步和状态同步常用的场景了

常用场景:

帧同步的常用环境:

  1. 实时竞技类游戏:射击游戏、格斗游戏、赛车游戏等需要玩家实时操作和快速响应的游戏。
  2. 多人合作游戏:团队合作游戏,如合作射击游戏、合作策略游戏等,要求玩家之间的操作和游戏状态高度一致。

状态同步的常用环境:

  1. 回合制游戏:棋类游戏、卡牌游戏、回合制策略游戏等,玩家的操作在每个回合结束后进行同步。
  2. 大型多人在线角色扮演游戏(MMORPG):玩家在一个大型的虚拟世界中进行游戏,需要同步玩家的位置、状态、任务等信息。

猜你喜欢

转载自blog.csdn.net/asdasd121312dasd/article/details/132629886