如何在游戏中实现时间旅行?


10

我想知道如何在游戏中实现时间旅行。没什么超级复杂的,只是像Braid中的时间倒转一样,用户可以将倒带/快进时间缩短30秒或类似时间。

我在网上搜索了很多内容,但结果通常是指使用时间,例如“ 3:00”或计时器等。

我唯一想到的是使用2个数组,一个数组用于播放器的x位置,另一个数组用于播放器的y位置,然后迭代这些数组并将角色倒带/快进时间放置在该位置。那行得通吗?如果可行,阵列必须有多大,我应该多久存储一次玩家的x和y?如果不起作用,我还能尝试什么?

提前致谢!


11
您不阅读新闻(ust.hk/eng/news/press_20110719-893.html)吗?他们只是表明不可能进行时间​​旅行。因此,不可能进行编码。

您需要考虑时间旅行的可能语义,只有在此之后,您才可以开始考虑实现。
圣保罗Ebermann


2
学习一些矢量数学。如果您建议使用两个单独的数组,则表明您从未使用过它们。我认为它们对于游戏程序员来说至关重要,因为它们可以简化很多事情。
doppelgreener

5
import universal.back2future.FluxCapacitor;
2011年

Answers:


6

数组的想法几乎是在Braid中实现的。当唯一作用在角色上的是重力,键盘/操纵杆输入和其他角色时,您几乎只需要存储每一步的位置和速度即可了解有关该角色的所有重要信息。如果您每个角色每秒存储10个快照,那么一个角色的历史记录在一分钟内仍不到50K-在大多数系统上易于管理,并且您还可以找到比这更有效的方法。


这是正确的轨道。例如,存储活动命令:带有时间戳的按键。如果系统是确定性的,则可以推断大多数其他行为。10 fps跟踪器适用于倒带系统,只要保留了实际命令,实际上可以改变对象的状态或状态,就可以接受甚至更少的跟踪器。
卡明顿2011年

4

阅读命令模式。它提供了撤消动作(以及以后再做)。这不仅可以处理飞船的位置,还可以处理玩家采取的所有动作。

但我认为您的阵列想法也很合理。


可能不是一个好主意-除了占用更多内存(每次将实体的速度添加到其位置时,都需要将其存储为“动作”),它几乎需要定点数学运算,因为如果使用浮点运算您的位置/速度的-点,(x+v)-v可能不等于x
BlueRaja-Danny Pflughoeft

1
@BlueRaja-不知道该方法在哪里占用大量内存。以100 FPS的速度存储最后10秒时,您需要存储1000个n-tupel命令,其中n最多为5个左右。或者,甚至更好的是,您仅在每个帧中存储绝对位置,并且对于倒带,只需沿该路径向后动画角色即可。这也将消除任何可能的浮点问题,并使您完全回到起点。
Hackworth

3

而不是拥有两个单独的数组,您可能应该有一个描述玩家位置的类(Java中可能已经有一个Point类……最近我是C#家伙),并使用一个单独的数组来保存过去的位置。

您需要设置一个“环形缓冲区”,这意味着当您到达数组的末尾时,您将循环回到数组的开头,从而覆盖最早的条目。如果您时光倒流,则相反(当您到达起点时,圈出终点)。

如果要保留30秒的过去数据,则要预分配空间并使用固定大小的数组时,需要知道帧速率。如果您以10帧/秒的速度渲染游戏,则乘以30秒,即300个元素。



1

就像Erik J所说的那样,将玩家的过去位置作为一组点对象存储在环形缓冲区中听起来很合理。

但是,我建议使用队列来实现缓冲区。更新比数组便宜得多,而且您不必事先知道帧速率:

update():
   time_queue.push(player.positions)
   if current_time() - start_time > n:
       queue.pop()

这还没有考虑变化的帧速率,或者如果您实际进行任何时间旅行,该怎么办,所以我建议您在每个条目中存储一个时间戳,并检查一下:

update():
    time_queue.push({
        'pos': player.positions,
        'time': current_time()
    })
    first_entry = queue.peek()
    while current_time() - first_entry['time'] > n:
       queue.pop()
       first_entry = queue.peek()

希望这可以帮助!


1

有一种叫做Memento的设计模式,我认为这是《辫子》这类游戏的起点

记忆模式是一种软件设计模式,可以将对象恢复到其先前状态(通过回滚来撤消)。

记忆模式由两个对象使用:发起者和管理员。发起者是一些具有内部状态的对象。管理员将对发起者进行某些操作,但希望能够撤消更改。看守首先要向创建者索要纪念品。然后,它执行将要执行的任何操作(或操作序列)。要回滚到操作之前的状态,它将纪念对象返回给发起者。纪念品对象本身是不透明的对象(看守不能更改或不应该更改的对象)。使用此模式时,请注意发起者是否可以更改其他对象或资源-记忆模式可在单个对象上运行。

http://en.wikipedia.org/wiki/Memento_pattern

此处的特殊信息:http ://dofactory.com/Patterns/PatternMemento.aspx


2
我看不出这应该如何帮助。看起来这是一次“即时回滚”,而OP则要求像Braid一样平滑。也许我看错了什么?
o0'。

这种模式并不意味着一次回滚,例如,您可以创建动作的“时间轴”。这是有关此模式用法的巴西人博客文章:abrindoojogo.com.br/padroes-de-projeto-memento 这是Flash中的示例:abrindoojogo.com.br/files/fasteroids.swf移动:箭头| 拍摄:太空| 倒带操作:退格
Marcelo Assis,

1

XBox360发行了一款涉及时间操纵的游戏。这太平庸了,所以我现在不记得标题了。无论如何,在针对开发人员的采访中,他们概述了如何管理时间操纵:

每X帧(X值越低,导致操作越细化),您将在那时获取游戏世界的“快照”,并将其与游戏中的时间相关联。

在正常情况下进行游戏时,时间的推移,反应的每个输入都会有助于将来某个时候设置的快照。

然后,游戏世界在当前时间的快照和将来的快照X帧之间进行迭代。

然后,当您想倒转时间时,只需将时间的方向设置为倒退,以便在过去的当前X帧和快照X帧之间进行迭代(同时禁用创建未来快照的功能)。


+1有关快照的粒度。
奥马尔·库赫吉

0

您可以简单地将游戏的虚拟时间视为另一个类似于空间的维度。因此,从外部开始的时间旅行是游戏虚拟宇宙中的简单n + 1维运动。

假设在没有用户输入的情况下确定用户行为的某种用户交互和某种物理系统,您需要记录的只是用户交互的效果(例如,n + 1维速度/加速度矢量的变化) ,因为您的物理学应该是可逆的。

这样,您将需要更少的内存来计算任何给定时间坐标下游戏宇宙的状态。


正如我在另一条评论中提到的那样,视频游戏中的物理学通常不是时间可逆的,因为当使用浮点数时,它(x+v)-v可能不等于x
BlueRaja-Danny Pflughoeft

0

假设一个实体具有速度,旋转,x和y位置。这些都是加速度的基本运动状态,值,无论您称其为什么。您可以通过两种方式保存数据:
1.保存旋转,x和y位置
2.保存旋转,x速度和y速度

如果速度固定,则也只能保存旋转,或者两个轴仅保存一个速度。

在游戏中,必须保存轮换,除非您的实体具有静态轮换,否则大多数情况下是不需要的。

就是说,有必要为多个值使用对象列表。如果您有一个不错的计时器系统(例如,每秒调用更新方法20次,因此是fps无关的),则可以创建一个20 * 30对象的数组来存储最近30秒所需的移动值。不建议使用简单的数组,因为您必须将每个元素在每次更新调用时向左移动一个索引。

基于此,您可以浏览列表或返回的内容。如果您真的想获得“逼真的”效果,请对所有移动对象使用此技术。但这与游戏设计有关。

如果要销毁物件,请记住将它们集中起来,以确保您不会对整洁的朋友Garbage先生施加压力;)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.