实时多人游戏同步方案:不同架构的对比

探讨 Unity 实时多人游戏的现状,不同游戏类型中的不同网络架构。

网络架构模式

游戏开发者使用各种网络架构模式来确保多人游戏中玩家之间可靠且快速的互动。每种模式都有其自身的优缺点,选择合适的模式取决于您正在使用的特定游戏类型和互动场景。

在本节中,我们将讨论以下模式:锁步、回滚、快照插值和延迟补偿。此外,我们将讨论最适合不同类型或游戏的模式。

锁帧(LockStep)

**锁帧(LockStep)**是最古老的网络游戏同步方法之一,如今仍然经常使用。虽然这种架构可以采用多种形式,但我们将重点介绍最常见的实现,然后讨论必要的条件、限制和可能的配置。

在锁步架构中,每个玩家将其输入发送到其他所有玩家,然后在收到所有玩家的输入后立即推进其模拟------就是这样!游戏在互联网上完全同步,使用非常少的带宽,每个玩家始终看到事件的展开方式与其他所有人完全相同。

为了使游戏与锁步架构兼容,必须满足几个条件。让我们讨论一下。

确定性

锁步架构的主要要求是游戏模拟必须支持严格的位级[确定性](https://www.whatgamesare.com/determinism.html)。由于网络代码只同步输入,因此游戏模拟必须在每个帧中使用相同的输入数据在每台机器上计算出相同的结果。否则,游戏模拟将不同步、发散并偏离彼此------最终导致游戏看起来完全不同。

这通常是一个难以满足的条件,游戏必须经过精心设计才能保持确定性。开发人员通常在每个帧或帧中的多个点检查游戏状态校验和,并将这些校验和在参与者之间进行比较,以帮助跟踪和修复在游戏测试期间发生不同步的非确定性来源。

此外,任何使用浮点运算的游戏(即大多数现代游戏)都需要额外的考虑。如果您的游戏在多个平台上运行,由于平台和编译器之间的差异,浮点确定性可能特别难以实现。每个编译器可以使用不同的指令集、重新排序指令或自动矢量化。每个系统都可以以不同的方式实现超越函数,例如余弦、正弦和正切。所有这些都可能导致平台之间甚至构建之间出现不同步。一些开发人员完全使用定点运算或软件模拟浮点运算来实现其游戏模拟,以绕过使用浮点数产生的非确定性。

其他非确定性来源包括使用不同的种子生成随机数或以不同的顺序处理对象,例如物理中的接触。所有这些考虑因素也极大地限制了可以用作游戏模拟一部分的第三方库,例如碰撞检测库、物理引擎等。因此,这对于许多类型的游戏和引擎来说可能不切实际。

固定帧率

锁步还要求所有玩家同步每个输入和滴答所代表的时间单位。换句话说,游戏将以固定的帧率进行。一些游戏将渲染帧率锁定为与固定模拟帧率匹配。其他游戏允许以任意帧率进行渲染,并在固定滴答结果之间显示插值。

问题和限制

虽然锁步架构是最容易实现的架构之一,并且没有视觉伪影,但它存在一些问题和限制。在某些情况下,可以通过对游戏实现做出一些妥协来克服这些限制。在其他情况下,这些限制可能只是限制了这种架构对特定游戏的适用性。

输入延迟

锁步通过等待直到收到所有相关信息才推进,从而防止任何延迟引起的视觉伪影。这种等待有一个缺点:输入延迟。

"输入延迟"通常是指用户按下按钮到在屏幕上看到响应之间的时间。从用户的角度来看,当他们在屏幕上看到该输入的结果时,他们会感知到对他们输入的响应。如果用户必须等到所有其他玩家收到并处理他们的输入才能看到此响应,这会导致明显的输入延迟。

在对反应性要求很高的游戏中,例如射击游戏,输入延迟可能是关键因素,因为它会使游戏响应速度变慢,更难玩。

回滚

接下来,回滚是一种流行的网络代码架构,广泛应用于现代竞技游戏,尤其是在格斗游戏中。

回滚可以看作是经典锁步架构的扩展。在回滚架构中,玩家在每一帧发送他们的命令,并在不等待其他玩家的命令的情况下继续他们的游戏。游戏在不等待来自远程玩家的数据的情况下进行------这被称为"客户端预测",因为远程输入数据尚不可知,客户端必须对其他玩家的未来行动做出假设。

与锁步架构(它提供帧到帧的完美顺序,但存在输入延迟)相比,回滚架构提供即时命令响应,但以顺序为代价。

在回滚过程中,游戏会进行,并且一旦本地玩家的命令发送出去,就会立即显示出来。但是,由于尚未收到来自远程玩家的命令,因此显示的信息是预测。一旦收到来自远程玩家的数据,就必须将此新信息与预测进行协调。如果信息与预测不匹配,则游戏将回滚以"纠正"错误。

什么是"回滚"?

假设在客户端准备渲染第 7 帧时,收到了来自远程玩家的第 5 帧的新数据。在这种情况下,客户端需要执行以下步骤:

  1. 加载/恢复整个游戏的状态,使其处于第 4 帧,即所有命令都已知的上一个不可预测帧。

  2. 使用第 5 帧的原始本地命令以及从远程玩家新收到的命令,将游戏移动到第 5 帧。

  3. 通过对每一帧应用本地命令继续向前推进,直到我们到达当前帧(在我们的示例中,这是第 7 帧)。

完成这些步骤后,我们可能会注意到,远程玩家在第 5 帧中的操作可能导致的结果与预测的结果不同;现在将在游戏中显示这些更正后的结果。

因此,在这种情况下,"回滚"意味着游戏"回滚"到所有内容都已知的最后一帧,然后使用新信息"重播"向前。这提供了纠正预测错误的能力。

需要注意的是,为了使此方法有效,游戏必须能够快速保存和恢复其完整状态,以及使用任意命令向前移动任意数量的帧。根据游戏的复杂性,这可能需要大量的计算资源。

快照插值

快照插值是一种由游戏 Quake 推广的技术,此后已广泛应用于源自 Quake 的游戏和游戏引擎。事实上,这种模型特别适合射击游戏。

快照插值方法基于游戏对象两个独立的时间流的概念:一个反映过去对象的状态,另一个反映未来对象预期状态。

客户端(玩家)将其命令发送到服务器,服务器处理这些命令,更改游戏状态,然后将游戏当前状态的"快照"发送回客户端。此快照包含有关游戏中的所有对象在创建快照时状态的信息。

为了保持游戏的响应速度,客户端会立即将部分命令应用于某些对象,预测其行为。这会导致对象在玩家的屏幕上同时以不同的状态存在:

  • 插值对象以它们在过去某个时间点的状态表示。

  • 预测对象以它们在未来某个时间点预期存在的状态表示。

这会产生一种有趣的动态,例如,当您预测的角色试图躲避一个正在插值的传入弹丸时。这可能比看起来更难,因为您的角色正在未来移动,而弹丸则在过去。

尽管如此,这种模型还是有一些优点:

  • 游戏会立即响应玩家命令;与锁步模型不同,不需要输入延迟。

  • 与完整的回滚架构相比,客户端需要更少的处理时间。

  • 对象在从服务器获得的已知状态之间进行插值,因此对象只通过它们已经处于的状态。

需要注意的是,为了有效地使用这种模型,游戏必须能够快速处理和传输游戏状态的快照,以及立即响应玩家命令。

不同游戏类型的最佳架构

每种游戏类型都会对网络延迟、稳定性和吞吐量施加其自身的限制。例如,MMO 游戏需要高吞吐量、低延迟和高稳定性。同时,第一人称射击 (FPS) 游戏需要低延迟和高吞吐量。在这两种类型中,建议使用具有权威游戏服务器和基于状态和输入的数据交换的服务器-客户端拓扑。

下表提供了不同视频游戏类型的网络需求、数据交换格式、推荐的网络拓扑和网络模式的比较概述。

通过分析此表,我们可以得出一些结论:

  1. 网络需求在很大程度上取决于类型:例如,RTS 和 FPS 游戏需要低延迟才能确保流畅且逼真的游戏体验。

  2. 数据交换格式也因类型而异:大多数游戏使用状态和输入交换,但有些游戏,例如 RTS 和动作游戏,只使用输入。

  3. 网络模式和拓扑是根据每种类型的特定需求选择的:动作和体育游戏通常使用预测和回滚,而 MMO 和 RPG 游戏通常使用快照预测和插值。

继续前进

每款游戏都有其自身的一套需求和类型交叉,这会对其网络互动施加其自身的限制。在许多情况下,选择经过验证的解决方案将比独立开发更好。

在这篇文章中,我们回顾了实时多人游戏中网络架构的主要模式。我们还汇总了一个针对不同类型推荐解决方案的通用表格。当然,这些建议并非最终的和通用的,但它们可以作为您选择架构解决方案时的起点。

相关推荐
王维志8 小时前
在Unity中使用Epplus写Excel
unity·游戏引擎·excel
tealcwu16 小时前
【Unity基础】对比Unity中碰撞类与触发类交互机制
unity·游戏引擎·交互
杳戢1 天前
凹凸/高度贴图、法线贴图、视差贴图、置换贴图异同
unity·图形渲染·贴图·技术美术
我是汉堡请多指教1 天前
Unity学习---IL2CPP打包时可能遇到的问题
学习·unity·游戏引擎
suzh1qian2 天前
Unity类银河战士恶魔城学习总结(P129 Craft UI 合成面板UI)
学习·unity·c#·游戏引擎
tealcwu2 天前
【Unity踩坑】Unity编辑器占用资源过高
unity·编辑器·游戏引擎
|Ringleader|3 天前
【Unity Bug 随记】unity version control 报 xx is not in a workspace.
unity·bug·版本管理·uvc
Leoysq3 天前
【UGUI】Unity 游戏开发:背包系统初始化道具教程
unity·游戏引擎
Padid3 天前
SRP 实现 Cook-Torrance BRDF
c++·笔记·unity·游戏程序·图形渲染·着色器