This page looks best with JavaScript enabled

Unity::帧同步 预测回滚

 ·  ☕ 4 min read

备份数据

每个Entity 的所有 component都实现 IBackup ,里面的数据都写入 stream里面

#回滚数据

  1. 从二进制数据流里面还原LogicEntity数据
  2. 还原LogicEntity相关引用关系
  3. 还原View层VEntity,重新绑定 LogicEntity 关系,
  4. 对比 逻辑层和View层Entity,如果VEntity对应的learn LogicEntity已经不存在了,要丢回回收池。
    如果有LogicEntity对应的 VEntity不存在要创建出来,把最新的逻辑层数据更新到视图层(位置,动作等)

对整个内存块进行备份和还原

#预测 – 获取上一帧玩家的输入作为当前帧的输入 ,预测量,网络差的时候 预测多一点

预测帧和 服务器帧 进行对比
服务器的帧CMD: [ServerFrame 1][ServerFrame 2][ServerFrame 3][ServerFrame 4][ServerFrame 5]
客户端本地CMD: [ClientFrame 1][ClientFrame 2][ClientFrame 3][ClientFrame 4][ClientFrame 5]
                                    [确认帧]

======================同步
验证对比 ServerFrame 和 ClientFrame buffer数据。 如果一样表示 预测帧是正确的,更新确认帧变量,否则就要回滚

RingBuffer

MissFrame 需要客户端向服务器请求包

#追帧 当前帧数和服服务器的帧数不一样时。从当前帧快速计算到服务器的帧数

减少丢包概率 服务器可以发送 冗余 数据 当前tick 100 帧 可以 发送 97 98 99 100 的数据包给 client

多线程如何同步

可靠UDP如何实现

设计数据包结构
定义协议头
数据包标识
序列号同步
文件指针定位
数据大小信息
重发机制
协议的错序重排机制

Unity实现协程的原理

yield的运作机制: 可以用返回的迭代器来控制代码块的运行。它支持将一个函数用yield切分比函数粒度更小的"代码块",并且让用户来控制(通过movenext)每个代码块的执行时机
IEumerator  MoveNext MoveNext
yield return 不同的条件,根据条件 调用 MoveNext
StartCoroutine 注册协程到协程调用器

网络同步 移动同步解决方案

  • ROLE_Authority :: 服务器上的角色
  • ROLE_AutonomousProxy, :: 被玩家控制 本地角色 :: 接收玩家的Input输入,开始进行本地的移动预表现,等收到服务器的最新位置信息时候,对比位置作出调整,移动是否可以被延迟发送,判断当前的客户端网络速度如何,如果比较慢则,保存到PendingMove,取消本次给服务器消息,下次Tick的时候,就会判断当前的新的移动是否能与上次保存的PendingMove合并
  • ROLE_SimulatedProxy :: 完全通过服务器同步来控制
    UE的思想就是,将所有的移动的关键信息都数据化,这样移动就可以自由的存储和回放。为了节省带宽,提高效率,我们也就可以想出各种办法来减少发送不必要的消息,对于一个没有移动过的玩家,理论上我们甚至都可以不去同步他的移动信息


    移动组件详解

状态同步优势

1.它的安全性非常高,外挂基本上没有什么能力从中收益。
2.状态同步对于网络的带宽和抖动包有更强的适应能力。
3.在开发游戏过程中,它的断线重连比较快,如果我的游戏崩溃了,客户端重启之后只需要服务器把所有重要对象的状态再同步一次过来,重新再创建出来就可以了。
4.它的客户端性能优化优势也比较明显,比如优化时可以做裁剪,玩家看不到的角色可以不用创建,不用对它进行运算,节省消耗。

C# 引用类型 值类型 拆箱 装箱

装箱的过程就是将⼀个值类型分配给 Object 类型变量的过程。当你装箱⼀个值时,CoreCLR 会在堆上分配⼀个新的对象,并
将该值类型的值复制到该对象实例。返回给你的是⼀个在托管堆中新分配的对象的引⽤。

C# 注意点和优化点

使用+号连接字符串时,值类型需要通过装箱操作转化为引用类型才可以添加到字符串中。但是装箱操作对性能影响较大,     因为在进行这类处理时,将在托管堆中分配一个新的对象,原有的值复制到新创建的对象中。
使用值类型的ToString方法可以避免装箱操作,从而提高应用程序性能。
int num=1;
string str="go"+num.ToString();
运用StringBuilder类(循环中)拼接长字符串

避免使用ArrayList。

可复用的对象静态化处理,避免频繁GC

Dict  key 优化 使用int 不要用  string

重写Equals()方法时也应当重写GetHashCode()方法,同时提供operater==()操作

构造函数传参有gc ,不定参有gc  param[] 委托gc  

#AABB & OBB碰撞 分离轴、GJK


AABB构造:
矩形包围盒可采用:
①中心点加宽高
②者对角线两个点。

OBB构造:
长方体构造:
①8个顶点
②6个面
③3组平行面
④一个顶点和三个彼此正交的变相量
⑤中心点,旋转矩阵,3个1/2边长
一种较好的妥协方式是:只存储旋转矩阵中的两个轴,只是在测试时利用叉积计算第三个轴,相对来讲,能够降低CPU的操作开销,还能节省三个浮点数分量,降低了百分之20的内存消耗
–《实时检测碰撞算法技术》第4.4章

四叉树优化空间探测 – 空间划分算法

  • 2d 网格划分 — 四叉树 — 松散四叉树
  • 3d 八叉树 层次包围盒树
    AABB包围盒、包围球、方向包围盒OBB

A* 寻路

open list 一个记录下所有被考虑来寻找最短路径的方块(称为open 列表)
clost list 一个记录下不会再被考虑的方块(成为closed列表)
F = G + H
G = 是从开始点A到当前方块的移动量
H = 是从当前方块到目标点的移动量估算值

Share on

James
WRITTEN BY
James
Unity Developer