游戏中的网络同步
游戏卡顿
瞬移
明明打中了却 没有打中?
在此之前我们先看看 网络延迟抖动的 带来的问题:
定时向服务器报告位置, 服务器负责转发 到其他的客户端:
其他客户端要是直接显示出来(没有平滑移动), 就会产生顿挫 (瞬移)
理想状态的下(不考虑网络不稳定的情况),要是每秒 超过 24 帧 也是没有问题的,人眼会自动的 弥补中间的位置 产生连续的画面,类似电影。 但现实情况下确实打脸的 网络延迟 和抖动 无处不在! 言外之意就是我们 很多时候在处理的都 网络抖动和延迟带来的问题
网络 延迟 和抖动
- UPD : 不可靠 无序 延迟 抖动
- TCP: 可靠 有序 延迟 抖动
- 延迟一般在 200ms 以内,玩家是不会有明显感觉的
- 网络延迟受地域 影响比较大
- 网络抖动带来的 降频:
客户端按照固定频率发送服务器 7帧,转发到另外一台客户端 其余四帧几乎同一时间到达,
实际效果类似服务器就发送了三帧
例如下面这个图:
客户端33帧发送,时间间隔 理论值0.03秒; 但是在另外一个客户端 相隔0.03秒的同步包 平均只有 15帧。 发送端尽管帧率 33 帧,但是由于网络延迟,抖动等原因,实际到达帧率较低!
网络测试的工具:
- 限制网速的 工具 netlimiter
- 增加延迟的 工具 clumsy
-
网络同步中 位置移动的 优化算法:
1. 插值算法
客户端 收到 同步协议后, 客户端不直接 设置实体到 目标位置。 而是让实体以一定速度移动到目的地
代码层面如下:
插值算法的缺点:
用误差换取平滑,对延迟要求不是很高的 游戏来讲 可以适用
玩家1 从 B点 移动到 C点的过程中, 玩家2 才刚刚看到 坦克 从 A点 移向 B点
插值算法的分类:
- 瞬移
- 匀速插值 (使用比较多)
- 匀加速
- 匀减速
- 曲线等等
2. 预测算法
在某些有规律可循的条件下,如 匀加速 匀减速 运动中, 能预测坦克接下来的位置。 提前走到预测的位置去
代码如下;
- 预测算法的优点:
适用于高速移动物体,例如赛车 匀速 匀加速下可以 预测下一个位置的情况的下:
假设 匀速前进吗,玩家1 经过 B点 是发送位置, 玩家2 根据 pos= pos0+v*t 预测下次收到包 应该移动到 C点。 玩家2
让坦克 移动向 C点, 这样一来玩家1 和玩家2 误差就会很小
- 预测算法的缺点:
当玩 家1 突然停下来 或者被打爆,玩家2看到的坦克还会继续 向指定位置移动一段距离,然后再回到 停下来的位置或者爆炸的位置,吃鸡里面就经常会出现这种情况
3. 缓存列队
相对于 插值算法 和 预测算法,都是相对于 最后一条消息 做的插值或者 预测。在网络延迟或者波动较大时都还是会 都可能会出现 瞬移或者拉扯
将受到的消息缓存,安装平均的时间 逐一播放;
缓存队列算法的优点:
尽管接收到的 消息是不平均的 有抖动的,但是可以平均的 表现出现。
缓存队列算法的缺点:
使用更大的延迟 换取 平顺 抵消 抖动
代买如下
同步方法的归类:
游戏逻辑是: 客户端运算 还是 服务器运算
- 客户端 :怪物生成,碰撞 计算都是客户端完成 服务端转发 服务器计算量减少,
- 服务器端 :怪物生成,碰撞 计算都是服务器端完成 转发 服务器计算量大,并且 服务器难度加大(游戏中的库 碰撞 物理引擎 AI 等等) 在服务器无法使用
一般 需要我们可以 权衡 客户端和 服务器的功能,比方说生成可以的 服务器端, 碰撞客户端。这个都可以按照 实际项目需求来做一个权衡
帧同步 还是 状态同步:
- 状态同步 :客户端发送 数据/指令 到服务器, 服务器计算并 返回结果 转发到所有客户端
- 帧同步 :简单来说就是 服务器 只是转发 不参与计算
摘要 其他地方的解释:
- 状态同步:客户端发送操作给服务端,服务端接收所有客户端操作数据,处理计算逻辑得出结果,发送数据更新所有客户端
- 帧同步 :客户端发送操作给服务端,服务端转发所有客户端操作数据,所有客户端都通过随机因子保证每次得出结果一样(随机因子保证一样,因为比如浮点数可能会影响到准确性,今儿导致结果不一致,或者随机因子也可以有服务器给,直接保证一样)
- 状态同步:指的将其他玩家的状态行为同步的方式,一般情况下AI逻辑,技能逻辑,战斗计算都由服务器运算,只是将运算的结果同步给客户端,客户端只需要接受服务器传过来的状态变化,然后更新自己本地的动作状态、Buff状态,位置等就可以了,但是为了给玩家好的体验,减少同步的数据量,客户端也会做很多的本地运算,减少服务器同步的频率以及数据量。
- 帧同步:RTS游戏常采用的一种同步技术 ,上一种状态同步方式数据量会随着需要同步的单位数量增长,对于RTS游戏来讲动不动就是几百个的单位可以被操作,如果这些都需要同步的话,数据量是不能被接受的,所以帧同步不同步状态,只同步操作,每个客户端接受到操作以后,通过运算可以达到一致的状态(通过随机种子保证所有客户端随机序列一致),这样的情况下就算单位再多,他的同步量也不会随之增加。
延迟补偿算法:
延迟补偿算法实现起来比较复杂,实际使用并不多。
如下图所示:当玩 家1 和 玩 家2 存在 不同步的时候。玩家2在 91帧 开炮?打不打的中?
此时的服务器 运行情况:
应为 玩家2 在91 帧开了一炮,由于使用的是状态同步(逻辑服务端计算)。所以服务器强制 回溯到 91帧。进行计算。所以在 91帧的位置 玩家2 是可以打到坦克的,
延迟补偿算法 是游戏服务器端执行的一种策略, 处理用户命令使服务器回退到 客户端 发送命令的准确时间。这样的处理 是倾向于 实际击打 给玩家带来的乐趣(大家吃鸡的时候, 有没有遇到过 被汽车碾压过后发现 汽车回退到你前面一点地方炸掉了)。使玩家2 体验更好。因为 此时的 玩家1 心理期待 没有 玩家2 高
延迟补偿算法 利端:
- 以牺牲真实性来弥补 攻击行为的体验,本质上一种折中的 选择
- 对低延迟的玩家不公平,移动速度快, 可能已经跑掉了, 却又被打中了
- 对高延迟的玩家有利, 但对维护游戏世界 平衡还是有利的
对于游戏服务器功能:
- 保留多个帧的信息,如前20帧
- 必要时 回溯
帧同步算法:
帧同步的算法 在实际 游戏使用中 相对比较多
客户端 一直处在 收集 服务端 发来的指令。处理指令 结束的 的流水线中
帧同步的重点 在于 锁,
把 实时游戏变成 快速的 回合制游戏。回合制 特变快, 以至于我们 觉得是 实时的。
为了表现流畅,每一会合 我们可以包涵很多种帧
- 严格帧 同步:
如何有人卡了? 等待最慢的玩家,保证所有 人状态一致(一个人卡了 大家都卡了)
只有当 服务器 等齐了所有人玩家的 操作指令,才可以进行计算,进入下一个 会合 turn。 否则就要等待最慢的玩家。 之后再广播给所有 玩家。 才能保证一致性
严格帧同步利弊: 网络不稳定 容易大家一起卡。 优点 能保证一致性; (局域网游戏使用比较多)
如果有人延迟比较高,其他玩家 必须等待该玩家 跟上之后 再 继续计算。不存在某个玩家 领先或者 落后其他玩家的情况。 使用 严格帧同步(localstep)每个玩家的延迟 等于 延迟 最高的那个人;
- 乐观帧 同步:
采用 “定时不等待” 的乐观 方式
以 一定时间内的 不一致性 换取 体验
客户端 如果有延迟, 服务端 不等待:
延迟端缓存指令, 追赶执行,“起初王者荣耀中途退出之后 在进入的时候回 快速 播放之前的画面”
帧同步注意的事项:
同样的指令 * 同样的执行规则 = 同样的结果
- 不同平台 浮点数 一致性
- 使用 相同的 随机数种子;保证 客户端的 随机数一致
同步算法的选取
各种不同的 同步算法 都有自己适合的场景。 应该针对 自己的游戏 选取适当的 同步算法
帧同步适用的场景: