游戏的神奇魅力,迷惑着每一个外行人

游戏的神奇魅力,迷惑着每一个外行人

作为一名程序员,你有没有想过多人游戏是如何实现的?

对于外行来说,游戏是神奇的:两个或更多玩家在线分享共同的体验,就好像他们实际上存在于同一个虚拟世界中一样。 游戏看起来就像一个巨大的魔术多人在线游戏引擎,精彩而刺激,但作为开发者我们知道现实与我们所看到的不同,这只是一种幻觉。 您所体验到的共享现实实际上是您自己独特的视角和位置所感知的当时发生的事情的近似值。

1 点对点帧同步

最初的游戏是通过点对点联网的,每台计算机相互连接并通过网状拓扑交换信息。 你仍然会在 RTS 游戏中看到这种模型,并且出于某种原因它很有趣,也许是因为这是大多数人想到游戏网络如何工作的第一种方式。

处理游戏信息的基本思想是将游戏数据抽象并转换为一系列命令消息。 当每一次转换处理完之后,就直接演化成游戏的状态。 例如:移动单位、攻击物体、建造建筑物。 这一切都需要每台在线玩家机器,从初始化命令开始,运行完全相同的命令并转换数据。

当然,这只是一个过于简单的解释,还隐藏了很多细节,但通过这个基本思路,我们可以了解RTS游戏的网络是如何运作的。 如果您想了解更多网络模型,请点击:28.8上的1500个弓箭手:帝国时代及以后的网络编程。

这些看起来如此简单和优雅,但不幸的是它们有一些限制我们的因素。

第一个限制是,确保游戏状态完全确定性和一致是极其困难的,尤其是保持每台机器上每个转换的输出相同。 例如,在两台机器上路径略有不同的单位可能会较早到达并在一台机器上开始战斗并赢得战斗,而在另一台机器上可能会因到达稍晚而失败。 就像蝴蝶扇动翅膀会在世界的另一端引发飓风一样,随着时间的推移,微小的差异可能会导致两侧完全不同步。

第二个限制是,为了保证游戏中所有玩家的输出一致,需要等到所有玩家的当前回合数据到达后,才能模拟本回合的动作。 这意味着游戏中的每个玩家都需要等待网络延迟最高的玩家。 RTS 游戏通常通过提供即时音频反馈和/或播放圣歌(过渡)动画来掩盖这种延迟,但最终真正影响游戏的动作只有在这种延迟过去之后才能执行。

第三个限制是游戏中状态变化的同步是通过发送命令消息来同步的。 因此,为了让游戏中的玩家状态保持一致,所有玩家需要从相同的初始状态开始游戏。 这意味着每个玩家必须在开始游戏之前加入房间,然后一起开始游戏,虽然理论上可以有一些玩家稍后加入游戏,但要在正在进行的游戏中获得完全确定的起点难度相当大高,所以这种情况并不常见。

尽管存在这些困扰我们的限制,但这种模式仍然非常适合RTS游戏,并且仍然存在于当今的游戏中,例如《命令与征服》、《帝国时代》和《星际争霸》。 原因是RTS游戏包含超过数千个单元。 这些单位都有自己的状态需要同步,而且数据量太大,玩家之间交换起来很困难。 我们别无选择,只能通过这些游戏状态改变命令来进行同步。

以上就是点对点帧同步网络游戏模式的介绍。 对于其他类型的游戏,最先进的技术已经开始出现。 现在让我们从《毁灭战士》、《雷神之锤》和《虚幻》等经典游戏开始,观察动作游戏的技术演变。

2 客户端/服务器(c/s架构)

在动作游戏时代,上述帧同步限制在《毁灭战士》游戏中变得更加明显。 虽然在局域网上体验还不错,但对于互联网用户来说却是糟糕的体验:

虽然可以使用调制解调器通过互联网将两台 Doom 机器连接在一起,但一起玩它们会非常慢。 游戏连接范围从无法玩(例如:14.4Kbps PPP 连接)到稍微可以玩(例如:28.8Kbps 模式运行由 SLIP 驱动程序压缩的数据)。 游戏连接速度非常慢。 由于这些连接的效用很小,因此本文将仅关注直接网络连接。

这个问题是因为Doom网络部分最初只是针对LAN设计的,并且使用了前面介绍的点对点帧同步模型。 在每一轮中UI界面,每个玩家的输入信息(如关键按键等)都会与其他玩家同步通知,任何玩家必须等到所有其他玩家的关键按键信息都收到后才能播放这一帧动画。 然后才能模拟播放。

也就是说,你必须等待最延迟的猫(调制解调器)玩家的输入,然后才能转动(变形)、移动或射击。 只要想到上面的人写的“这些联系的边际效用”就会让人咬牙切齿和沮丧。

为了改变这种只有在局域网、大学网、大型企业才能获得良好的游戏连接的状况,就必须改变这种网络模式。 这成为现实并于 1996 年得到实施,当时 John Carmack 发布了 Quake,它用客户端/服务器 (C/S) 架构取代了 P2P 模型。

现在游戏中的玩家不再需要运行相同的代码并直接相互通信。 每个玩家的机器都是一个“客户端”,他们都通过称为“服务器”的机器进行通信和交互。 游戏的最终状态不再依靠各个客户端机器共同确认,而是由服务器决定最终结果。 每个客户端都充当哑终端,显示服务器上运行的实际游戏状态的近似值。

在纯c/s架构中,你不必在本地运行游戏代码,而是将一些输入信息如按键、鼠标移动、点击等发送到服务器。 服务器会更新你在游戏世界中的玩家状态,然后回复你的客户端一个包含你的角色信息和附近玩家数据的数据包。 所有客户端都会在每次消息更新之间进行插值预测,以提高每次状态更新期间对象的平滑移动。 这样,您就拥有了一个网络客户端/服务器架构游戏。

这已经是向前迈出的一大步。 游戏体验依赖于客户端和服务器之间的连接,而不是游戏中延迟最大的玩家。 这可以支持玩家自由地进入和退出游戏,同时多人在线游戏引擎,由于客户端/服务器减少了每个玩家的平均带宽,因此可以添加更多的在线玩家。

但c/s架构还存在一些问题:

我记得我做出了从 DOO 到 Quake 的所有有关网络的决定,但重要的是我使用了错误的假设来制作一款优秀的网络游戏。 我最初的设计目标是网络延迟用户模式>ISP模式>服务器>ISP模式>用户模式>客户端。 天哪,这太糟糕了。

好吧,我设置错误了。 我家里用的是T1宽带,所以不太了解PPP网络的生活。 我现在就修好它。

问题当然是延迟。

接下来,当约翰发布 QuakeWorld 时,他将改变这个行业。

3 客户端预测

在最初的《雷神之锤》游戏中,您可以感受到计算机和服务器之间的延迟。 例如,如果你按下前进键,那么在你可以真正移动之前,你需要等到数据包发送到服务器然后回复到你的客户端才可以真正移动。 按下按钮开火也需要在射击前进行同样的等待。

如果您玩过任何 FPS 游戏,例如《现代战争》,您会发现没有出现延迟。 那么FPS游戏如何保证你的动作在多人游戏的情况下不会显得延迟呢?

这个问题分两部分解决。 第一部分是客户端运动预测,由 John Carmack 为 QuakeWorld 游戏开发,后来合并到 Tim Sweeney 的 Unreal Network 模块中。 第二部分是延迟补偿,由 Valve 的 Yahn Bernier 在 Counterstrike 中开发。 所以在本章中,我们关注第一部分——隐藏用户移动的延迟。

约翰·卡马克 (John Carmack) 在撰写即将发布的《QuakeWorld》计划时说道:

我现在允许客户端预测用户的动作,直到服务器回复权威信息。 这是一个重大的结构性变化。 客户端需要了解物体的硬度、摩擦力、重力等一系列基本属性。 我很难过看到客户端只是作为一个终端而消失,但作为一个实用主义者,我必须超越这种理想主义情绪。

所以现在为了消除延迟,客户端需要运行更多的代码。 现在它不再是一个只是将输入发送到服务器然后插入返回信息的哑终端。 现在程序开发,客户端的机器可以运行部分游戏代码,在本地预测角色的动作并立即响应您的输入。

现在,当您立即按下前进按钮时,您的游戏将立即前进,您将不再需要等待客户端和服务器之间来回发送数据才能响应您的操作。

这种方法的困难不在于预测。 这种预测的工作原理就像正常的游戏代码一样——根据玩家的输入及时更新游戏角色的状态。 困难在于,当客户端和服务器对玩家角色的行为(动作)检查不一致时,客户端如何根据服务器信息进行修正。

现在您在想,嘿,如果代码在客户端上运行 - 为什么不依赖客户端的信息呢? 客户端可以运行角色模拟本身的代码,并且只需要在每次发送数据包时告诉服务器此信息。 如果每个客户端都向服务器发送相同的信息,告诉服务器“这是我当前的位置信息”,就会造成这样的问题。 客户端很容易被黑客攻击和控制,因此在角色扮演游戏中,作弊者可以立即躲避对手的技能攻击,或者在你开火时传送到你身后。

所以在FPS游戏中,每个玩家的客户端都可以尽快预测自己的角色进行操作和移动,但最终每个玩家的角色状态绝对是由服务器决定的。 正如 Tim Sweeney 在他的文章《虚幻网络架构》中所描述的:“服务器是主宰。”

这就是有趣的地方。 如果客户端和服务器之间存在不一致的情况,客户端必须根据服务器的信息进行更新。 然而,由于客户端和服务器之间存在延迟,服务器的纠正必须是过去的一个动作。 例如,如果信息从客户端到达服务器需要100ms,然后需要100ms返回,那么服务器所做的任何更正都将是客户端200ms前的行为,这正是客户端预测的时间角色的动作。

如果客户端的每一个动作都被服务器纠正,那么你会看到客户端被拉回原来的位置,因此客户端将无法进行任何预先预测的计算。 那么我们如何解决这个问题并且仍然让客户提前预测呢?

解决方案是在客户端创建一个缓冲区,然后用它来循环维护角色的状态和原始玩家的输入。 当客户端收到服务器发送的更正信息时,首先丢弃缓冲区中早于更正状态(服务器回复的)的状态信息,然后根据正确状态重放缓冲区中存储的输入信息(由服务器更正)。 这些重传的输入的范围是从正确状态到当前预测时间。 因此,实际上,客户端只是看似无形地“倒回并重播”本地玩家角色运动的最后 n 帧,同时保持世界其他部分不变。

这种方法可以让玩家在控制游戏时感觉不到延迟,同时还提高了客户端和服务器之间代码执行的一致性——在相同输入的情况下保持一致的结果。 当然,纠正很少发生,正如蒂姆·斯威尼这样描述的:

...对于客户端和服务器来说最好的事情是:服务器在所有情况下都是权威的。 几乎所有时候,客户端的模拟和服务器的数据都是一致的,因此客户端的位置很少被纠正。 只有极少数情况下,例如玩家被火箭击中或与敌人(怪物)相撞,客户端的本地情况可能需要修正。

也就是说,只有当玩家的角色受到某些影响玩家输入的外部事件影响时,玩家的位置(行为)才需要由服务器进行纠正,而这些是客户端无法预测的。 当然,如果玩家试图作弊,服务器会予以纠正。

本文为翻译文章。 请参阅原始版本的链接。 如果翻译有错误,请联系我。

来源:

多人在线游戏引擎_多人在线游戏引擎_多人在线游戏引擎

文章来源:https://blog.csdn.net/yhhwatl/article/details/72843369