《铸梦之路一》帧同步

帧同步解析

1.帧同步介绍

什么是帧同步?从字面意义上来看,肯定就是每帧的数据完全同步,即叫帧同步。
当然,都说了只是从字面意义上来看,所以他并非是完全正确。
帧同步是前后端同步数据以及保证多客户端帧数相同的一种手段,帧同步真正的核心并非是客户端与客户端之间帧数的同步。帧数同步只是帧同步的基础,最终导致多个客户端是否同步的罪魁祸首是数据同步。所以帧同步必须要做到多端数据计算完全一致性。即一个输入进来,服务端和客户端所计算出来的结果完全一致。哪怕是十个百个Android、IOS设备,在同一个输入的情况下,都等得到相同的输出。这才是帧同步真正的核心。最终也应了那句话:相同的输入+相同的时机=相同的输出。而相同的时机,则就是客户端与客户端帧间隔的同步。

2.帧同步实现流程

请添加图片描述

3.帧同步不同步的罪魁祸首

帧同步最大的难题不是帧数的同步,而是如何在不同的平台保证数据同步的一致性。
这里就衍生出一个问题了。
那么为什么会出现数据不同步的问题呢,原因呢?
这里博主要举个栗子:
现在有这么两组数据需要客户端与服务端进行计算,并校验结果是否一致。

  1. 1*1=?
  2. 1.48392*1.23773=?

这时候可以拿出计算器计算一下,1 * 1=1,而1.48392 * 1.23773则等于1.8366923016。当然如果你计算的和博主的不一样,那么就已经出现不同步的问题了。这里肯定就有人说了,那我直接强转int不就行了?方法是肯定的,答案是否定的。转成int要什么时候转?算之前转就是1*1=1,算之后转1.8366923016四舍五入就是2。一个计算竟然会有两种答案!惊讶吧。那这里还有人要问了,那我和服务端都商量好,算之前先转,不就同步了?当然还是那句口头禅,方法是肯定的,答案是否定的。别问为什么,问就是不同平台之间的硬件环境和系统平台的不一致导致了浮点数会计算出不一样的结果。硬件和系统五花八门,在不同的硬件和系统下你随便给一个非常复杂的浮点数让他们计算结果并保持一致性?那根本不可能。
所以我们要把命运掌握在自己手中,避免在帧同步中去使用浮点数(float double),因为我们无法确保他在不同平台之间结果的一致性。
但是我们能确保的是在不同的平台的之间,1+1都等于2。1 * 1都等于1。
所以这里我们的解决方案就是 定点数

当然还有不少因素是导致不同步的原因,例如:随机数,逻辑与渲染分离。

4.定点数

1.定点数学库

定点数是最常用的解决帧同步浮点数问题的解决方案之一,当然还有其他方案,例如:放大接断法,查表计算法等。
因为涉及到一致性的数据问题,以及Vector3、Rotation,Mathf等,所以一套完善的定点数学库是帧同步的核心基础。
2.查表计算

在计算三角函数的时候,会用到查表的方式获取相应的值。
用枚举法把度数对应的值存在一个数据结构表里,如xml或者json里,这样在用到三角函数计算的时候,我们实际上是查表获取对应的值,这样就会避免在各个平台或者硬件环境下计算结果不一样的情况。

3.放大截断法

其实就是使用整数去替代浮点数进行的一种计算。
首先确认放大因子,比如放大10000倍,实际上就是保留了小数点后四位,然后剩余的小数部分全部截取掉。逻辑层只参与运算,表现层需要表现的时候,在把该数值除以放大因子,这样就得到了原本的值。这样的话就能保证所有的逻辑计算都在整数层,也就不存在所谓的浮点数误差了。

5.随机种子(随机数解决方案)

随机种子用于随机数,是服务端于客户端达到随机数同步的一种技术手段。当游戏内某些地方需要进行随机时,则需要使用随机数。
随机数给与指定的随机种子后,随机出来的数相对于随机种子都是固定的。
何为随机种子?

这里博主举个栗子:
村长给了小王、小李、小张每人一颗小麦种子,让他们去种地。三个月后,小王、小李、小张的地里都长出了小麦。
村长给的种子,相当于随机种子,而小王、小李、小张、可以理解为三个客户端,客户端使用的随机种子是相同的,那么得到的结果也是相同的。服务端也同理。
这样就达到了不同的客户端、服务端,随机出来的数值是一致的,也就解决了使用随机数导致不同步的问题。
当然也要注意随机次数,如果一个客户端随机了三次,一个客户端随机了2次,那么肯定会导致不同步。
当然帧同步中一般也不会存在这种问题,毕竟帧数已经同步了,所有逻辑运算触发时机都在同一水平线上。但要注意逻辑代码是否会在某种特殊的情况下进行多次随机。

6.表现与渲染分离

1,抗网络抖动导致的渲染抖动(各种表现不平滑),不分离的话网络抖动导致逻辑抖动进而影响渲染,导致渲染画面卡顿跳帧。
2.逻辑层独立出来,可做服务端验算,如果前后端都为C#的话客户端服务端也可公用一套逻辑计算。
3.逻辑层可以单独线程处理计算,避免逻辑渲染共用主线程导致降低渲染效率,平摊cpu资源,保证渲染性能与效率最大化。这样做还有好处是:逻辑和渲染可各自发挥最大效能。
4.因为逻辑帧间隔比较大,所以渲染层需要根据逻辑层的数据来做曲线动画,以达到游戏的流畅性,这样的话不管逻辑帧间隔有多不规律,都能保证画面的流程性,而用户其实玩的就是一个画面游戏,这样的话在网络不好的情况下能让用户的体验倍增。
在这里插入图片描述
总结来说,渲染与逻辑分离并不能影响到帧同步,真正的帧同步是在每一个逻辑帧进行同步的。由于逻辑帧并不可能像渲染帧执行的非常频繁,一般都是1秒15次左右即可。这种情况下把渲染放到逻辑帧种去更新物体的位置,会出现非常明显的卡顿现象。
故因此,延伸出逻辑与渲染分离。
在逻辑层都保持一致的前提下,我只需要处理渲染表现即可,因为最终的所有的计算都在逻辑层,所以渲染只是一个表现,逻辑层的计算,以及数据的同步永远都是一致的。这也就是所谓的逻辑与渲染分离。
当然,还是绝对有必要这样做的。

7.UDP网络传输协议

为什么要选择使用UDP呢?
答案就一个字:快。
相较于TCP来说,在帧同步中UDP是最佳的选择。因为TCP丢包的机制,一旦发生丢包,TCP会将后续包缓存起来,等前面的包重传并接收到后再继续发送,这样虽然达到了数据的有序性,但是延迟会越来越大。而帧同步是非常依赖网络请求速度的,延迟越大,体验越差。因为UDP的简单快速的传输优势成为了帧同步的首选。

但是我们都知道UDP是面向非连接的,不可靠的。所以会丢包。

当然我们也可以通过以些技术手段去避免UDP丢包。
这样的话,在帧同步中使用UDP就是完全可行的了。解决UDP丢包的方案也有很多种,比如:EnetKCP 他们的原理都是在UDP上加一层封装,自己去实现丢包处理,消息序列,重传等类似TCP的消息处理方式,保证上层逻辑在处理数据包的时候,不需要考虑包的顺序,丢包等。

由于我们在底层已经处理好了UDP的丢包、顺序问题, 所以在真正使用的时候,除了快,是感觉不到和TCP有任何区别的。

在帧同步中,网络速度决定了游戏的体验,所以UDP网络库,基本都是帧同步必备技术。

8.定点数物理引擎

为什么要使用定点物理引擎?

因为Unity的物理引擎的碰撞计算是有使用到浮点数的。在非帧同步的的游戏中使用是没任何问题的,但是在帧同步中使用就会造成不同步问题。所以我们避免使用Unity的物理引擎。而是要我们自己基于定点数去实现一套物理引擎来保证计算的一致性。

如果游戏中需要物理引擎系统,可以在基于定点数的基础上去实现AABB、OBB的相互碰撞检测。
当然对绝大部分手游AABB、OBB碰撞就已经足够了。像王者荣耀的大型手游也就是使用AABB、OOB碰撞。因为王者世界中不需要重力,所以也不需要去处理重力。所以只需要关心与墙壁、玩家、弹道、范围伤害相碰撞即可。

总结来看,定点数物理引擎,也是帧同步的一大技术点。因为物理引擎计算的误差直接决定了影响到了帧同步。

9.结尾

总的来说,帧同步还算是挺复杂的,因为其设计的技术比较多,不仅仅是把每帧做成同步那么简单,当然具体的复杂程度要根据游戏来定。因为不同的游戏在使用帧同步所涉及的技术不同。比如王者荣耀,他涉及的帧同步相关的技术就很多了,基本涵盖了所有涉及到帧同步相关的技术,也不仅仅是博主写的这一点。

总的来说,还是需要我们多加努力,去钻研我们感兴趣的技术。因为兴趣是最大的动力。
当然你如果对帧同步感兴趣,可以关注下博主,博主后面会出多种不同类型的帧同步游戏Demo及案例。到时候可以多多交流。

暂时这么多,后续有想到的会在补充进来。

有梦想,就去追,你只管努力,其他的,交给天意!

10.帧同步RPG卡牌手游案例

下一篇:案例视屏地址:帧同步卡牌放置手游案例

[下一篇:帧同步RPG卡牌手游案例]

视屏教程地址:
文章来自于铸梦老师,铸梦之路系列课程。
想了解更多框架、帧同步技术、UGUI优化相关技术可在企鹅kt搜索 铸梦xy。

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值