从概念上讲,重播如何在游戏中发挥作用?

时间:2010-06-17 18:07:54

标签: design-patterns

我对如何在游戏中实施重播感到好奇。

最初,我认为只会有一个游戏中所有玩家/动作的命令列表,然后“重新播放”游戏并让引擎像往常一样渲染。但是,我已经看过FPS / RTS游戏中的重放,经过仔细检查,甚至像粒子和图形/听觉故障这样的事情也是一致的(这些故障通常 一致)。

那么这是怎么发生的呢。在固定摄像机角度游戏中,我可能只是将整个场景的每一帧写入存储的流然后只是重放流回来,但这对于允许您暂停和移动摄像机的游戏来说似乎不够周围。您必须在所有时间点存储场景中所有内容的位置(否?)。因此对于像粒子这样的东西来说,这是一个很难推动的数据,这似乎是游戏中游戏性能的重要吸引力。

12 个答案:

答案 0 :(得分:59)

我认为你最初的想法是正确的。要创建重播,您可以存储从用户收到的所有输入(以及接收它的帧编号)以及任何随机数生成器的初始种子。要重放游戏,您可以使用保存的种子重置PRNG,并为游戏引擎提供相同的输入序列(与帧编号同步)。由于许多游戏将根据帧之间传递的时间量更新游戏状态,因此您可能还需要存储每帧的长度。

答案 1 :(得分:27)

星际争霸和星际争霸:母巢之战有重播功能。匹配完成后,您可以选择保存重播以便稍后查看。在重放时,您可以滚动地图并单击单位和建筑物,但不能改变他们的行为。

我记得曾经观看过在原版游戏中播放的比赛的重播,但重播正在母巢之战中观看。对于那些不熟悉的人来说,母巢之战包含了所有原始单位和建筑物,以及各种新单元和建筑物。在原始游戏中,玩家通过创建计算机无法轻易抵抗的单位来击败计算机。当我在母巢之战中播放重播时,计算机可以访问不同的单位,它创建并用来击败玩家。因此,完全相同的重播文件会产生不同的赢家,具体取决于Starcraft播放文件的版本。

我总觉得这个概念引人入胜。似乎重播功能通过记录播放器的所有输入来工作,并假设计算机每次都以完全相同的方式响应这些刺激。当玩家输入被送入原始的星际争霸者重播时,游戏就像在原始比赛中一样。当相同的确切输入被送入Brood War重播器时,计算机反应不同,创建了更强大的单位,并赢得了游戏。

如果您正在编写重播引擎,请记住一些事项。

答案 2 :(得分:17)

有两种主要方法:

  1. 存储事件(例如播放器/ ai操作) - 就像你说的那样。
  2. 存储状态(完整游戏状态,对象的位置,连续时刻)。
  3. 这取决于你想做什么。有时存储事件更好,因为这通常会占用更少的内存。另一方面,如果您想提供可以不同速度和不同起点播放的重放,最好存储状态。存储状态时,您还可以决定是在每个事件之后存储它们还是f.e.每秒只有12或25次 - 这可能会减少重播的大小,并使其更容易倒带/快进。

    请注意,“状态”并不表示图形状态。更像是单位,资源状况等等。图形,粒子系统等东西通常是确定性的,可以存储为“动画X,时间Y:Z”。

    有时重播被用作反加热方案。然后存储事件可能是最好的。

答案 3 :(得分:10)

从技术上讲,你应该把你的引擎写成确定性的,这不是随机的。假设游戏中的角色瞄准对手的手臂并射击武器,则在所有情况下都应对对手施加相同数量的伤害。

假设炸弹在位置X引爆,爆炸产生的粒子应始终产生相同的视觉效果。如果您需要随机性,请创建一组随机数,在游戏播放时选择种子值,并将该种子值保存在重播中。

一般来说,游戏中的随机性是一个坏主意。即使像多人游戏这样的东西,你也不能让一半的玩家能够看到爆炸,而其他玩家不能仅仅因为他们没有获得正确的随机值。

让一切都变得确定,你应该没事。

答案 4 :(得分:10)

鉴于初始状态一系列带时间戳的操作,只需完成序列,因为记录的操作应该发生重播。

为了让随机事件重新发生完全相同,使用种子伪随机数并将种子保存在重播文件中。

只要您使用相同的算法从种子生成随机数,您就可以像在实时游戏中一样重新创建所有事件,而无需完整的游戏状态快照。

这将要求重播顺序观看,但这对于游戏重播来说非常正常(请参阅星际争霸2)。如果您想允许随机访问时间线,您可以以设定的时间间隔(比如每分钟)拍摄完整的状态快照,以设定的粒度跳过时间线。

答案 5 :(得分:7)

NVidia PhysX(一种常用于游戏的物理模拟引擎)能够记录物理场景的完整状态。这包含来自游戏引擎的任何驱动输入,这意味着您不需要像其他人建议的那样跟踪随机数种子。如果您进行此场景转储,您可以在外部工具(由NVidia提供)中重放它,这对于跟踪物理模型的问题非常方便。但是,您也可以使用相同的物理流来驱动图形引擎,这样您就可以进行普通的摄像机控制,因为只记录了驱动图形的物理场景。在许多游戏中,这包括粒子效果(PhysX包括一些非常复杂的粒子系统。)至于声音,我猜测它是逐字记录的(作为声音流),但我不确定。

答案 6 :(得分:4)

你最初的想法是正确的,对于真正复杂的效果,它们不会被完全记住。例如,魔兽争霸3重放系统不存储动画状态,或者在随机效果的情况下存储粒子效果等。此外,MOST事物可以从确定性方式的起点计算计算,因此对于大多数系统使用随机变量(例如,给出随机偏移的粒子爆炸),您需要的只是效果的时间和随机种子。然后你可以重新生成效果,而不必知道它最终会是什么样的......知道它正在通过一个确定的代码路径。

从概念上考虑,重播事件的时间表,您只需要用户操作。除了随机变量外,程序的反应方式完全相同。在这种情况下,您可以忽略随机性(如果效果看起来非常相同,或者它们是否可以随机重新生成,那真的很重要),或者存储种子值并伪造随机性。

答案 7 :(得分:3)

把我的两便士扔进去。

取决于你想要什么,重播可以通过

完成
  1. 录制视频缓冲区并稍后重播
  2. 每帧捕获对象状态并稍后重播
  3. 大多数时候,人们都希望进行互动重播,所以2.是最佳选择。然后,根据您的约束,有许多方法可以优化此过程

    • 确保系统是确定性模拟*,以便每个输入生成一致且预期的输出
    • 如果需要随机性,确保稍后可以完全再现随机数[看看使用伪随机数发生器PRNG播种,或使用固定随机集]
    • 将游戏元素划分为“机制”和“美学”元素。机械元素影响结果[例如柱子坍塌和阻挡路径],美学元素用于展示,不影响系统中的任何决策过程[例如像火花一样的视觉粒子效应]。

    这真是一个引人入胜的话题。我记得原始Xbox Wreckless的一个启动标题具有良好的播放功能。不幸的是,不止一次重播会搞砸;)

    是的,怎么会有人忘记Blinx Time Sweeper!将合并到实际游戏机制中的精彩互动重播!


    * =似乎有一些关于时间步进的评论。我在这里使用“模拟”来捕获此功能。在核心,您的引擎需要能够产生不连续的时间帧。即使重播帧的处理时间比原始帧更长或更短,系统也必须感知同一时间delta已经过去。这意味着记录每个记录输入的帧时间步长,并将此增量提供给您的引擎时钟。

答案 8 :(得分:2)

也许你可以简单地保存每个玩家发送的一堆命令。因此,您只需保存每个玩家发送的按键,而不是保存某个炸弹在某个时间点爆炸或者某辆汽车被摧毁。然后,在重播中,您只需模拟游戏,就像那些按下时一样。我觉得这有可能占用更少的空间,但我从来没有像这样的重播系统。

有趣的问题。我对它在专业游戏中的表现感兴趣。

答案 9 :(得分:2)

丹·布莱恩特

  

此外,记录随机种子不足以倒带   支持,因为随机进展不是一个可逆的过程   在依赖随机性的所有逻辑中没有特别的支持。   记录随机操作的结果更灵活   事件流的一部分。

这正是我最初的想法,当我试图弄清楚他们是如何做到这一点时,每次游戏重放总是一样的。在Doom中,我想到了拍摄的随机性:D。存储任何使用过的随机数,我发现它可能是一个解决方案。 那是在我看到关于孤岛危机技术的pdf论文之前。一些纹理在那里产生噪音,草或树的配置,似乎是使用固定可逆种子的伪随机化来制作它,所以你看到任何时候都没有看到噪音,树木和草的改变处置!

同时避免存放数百万棵树木和草井的位置。 显然,伪随机序列可以随时重放相同的内容,因为逻辑是固定的,只是制作一个假的统计随机数字序列。

答案 10 :(得分:1)

拥有一致的重播的问题与拥有一致的多人游戏一样(更好,更容易)。

正如其他人之前提到的,RTS游戏中的重放是通过记录所有输入来存储的(具有效果。滚动没有效果。) 多人游戏也传输所有输入

记录所有输入而不仅仅是猜测 - 有一个用于阅读Warcraft3重放的库,可以显示这个。

输入包含此答案的时间戳。

答案 11 :(得分:-1)

我相信在某些增量下游戏会拍摄一切状态的快照(一切)。然后,当重放发生时,可以使用线性插值的简单用法来填充“空洞”。至少这就是我认为它会如何完成。

你是正确的,记录输入是不可靠的/不保证相同的输出。游戏肯定要跟踪所有对象(或至少是重要对象)的状态