游戏中的时间倒转机制


10

我想知道游戏中的时间操纵机制通常是如何设计的。我对时间倒计时特别感兴趣(类似于最新的SSX或波斯王子)。

该游戏是2D自上而下的射击游戏。

我尝试设计/实现的机制具有以下要求:

1)除玩家角色外,实体的动作是完全确定的。

  • 实体采取的行动基于自关卡开始以来所取得的帧数和/或玩家在屏幕上的位置
  • 在关卡中的设定时间产生实体。

2)时间倒转通过实时倒转来实现。

  • 玩家的动作也被反转,它以相反的方式重放玩家的行为。播放器在反转时间内无法控制。
  • 反转所花费的时间没有限制,如果需要,我们可以一直反转到关卡的开始。

举个例子:

框架0-50:玩家在此期间向前移动20个单位敌人1在框架20处产生。敌人1在框架30-40期间向左移动10个单位玩家在框架45发射子弹子弹向前移动5个(45-50),并杀死敌人1框架50

反向将实时回放:玩家在此期间向后移动20个单位,敌人1在第50帧复活。子弹在第50帧再次出现。子弹向后移动5并消失(50-45)敌人向左移动10(40-30)敌人在框架20。

只是看着运动,我对如何实现这一点有一些想法,我想到了一个界面,该界面可以在时间前进或后退时改变行为。而不是这样做:

void update()
{
    movement += new Vector(0,5);
}

我会做这样的事情:

public interface movement()
{
    public void move(Vector v, Entity e);
}

public class advance() implements movement
{
    public void move(Vector v, Entity e)
    {
            e.location += v;
    }
}


public class reverse() implements movement
{
    public void move(Vector v, Entity e)
    { 
        e.location -= v;
    }
}

public void update()
{
    moveLogic.move(new vector(5,0));
}

但是我意识到这并不是最佳的性能,并且对于更高级的动作(例如沿弯曲路径的平滑移动等)会很快变得复杂。


1
我还没有看完所有这些内容(YouTube摇晃摄像头1.5小时),但也许乔纳森·布洛(Jonathan Blow)在他的游戏《辫子》中做了一些构想。
MichaelHouse

Answers:


9

您可能想看看Command模式

基本上,您的实体执行的所有可逆操作都作为命令对象实现。所有这些对象都至少实现2种方法:Execute()和Undo(),以及您需要的其他任何东西,例如用于正确计时的时间戳属性。

只要您的实体执行可逆操作,就首先要创建一个适当的命令对象。您将其保存在“撤消”堆栈上,然后馈入游戏引擎并执行。当您想倒转时间时,可以从堆栈顶部弹出操作并调用其Undo()方法,该方法与Execute()方法相反。例如,如果从点A跳到点B,则执行从B到A的跳变。

弹出动作后,如果您想随意前进和后退,则将其保存在重做堆栈中,就像文本编辑器或绘画程序中的撤消/重做功能一样。当然,您的动画还必须支持“倒带”模式才能向后播放。

对于更多游戏设计恶作剧,让每个实体将其动作存储在自己的堆栈中,以便您可以彼此独立地撤消/重做它们。

命令模式还有其他优点:例如,构建重放记录器非常简单,因为您只需要将堆栈中的所有对象保存到文件中,然后在重放时,将其逐个输入到游戏引擎中即可。一。


2
注意,由于浮点精度问题,可变的时间步长等原因,游戏中动作的可逆性可能是一件非常棘手的事情。在大多数情况下,保存状态要比重建状态安全得多。
史蒂文·斯塔德尼克

@StevenStadnicki也许吧,但是绝对有可能。C&C将军以这种方式离开了我的头脑。它具有长达8小时的长达一个小时的重播,最坏时重达数百kB,这就是我猜想,如果不是所有的RTS游戏都能够进行多人游戏,那么,这就是大多数情况:您可能无法传递数百个完整的游戏状态每帧的单位数,您必须让引擎进行更新。是的,这绝对是可行的。
Hackworth

3
重放与倒带是完全不同的,因为向前连续可重复的操作(例如,通过从x_0 = 0开始并在每一步中添加增量v_n来找到帧n,x_n上的位置)不一定向后可重复; (x + v_n)-v_n在浮点数学中并不始终等于x。说“解决”很容易,但是您所谈论的是潜在的全面检查,包括无法使用许多外部库。
史蒂文·斯塔德尼基

1
对于某些游戏,您的方法可能是可行的,但是AFAIK大多数使用时间反转作为机制的游戏都在使用与OriginalDaemon的Memento方法更接近的方法,在该方法中,每一帧保存有相关状态。
史蒂文·斯塔德尼基

2
通过重新计算步骤来倒回,但是每隔几秒钟保存一个关键帧呢?浮点错误不太可能在短短几秒钟内就产生重大变化(当然,这取决于复杂性)。它也显示可用于视频压缩:P
Tharwen 2012年

1

您可以看一下Memento模式;它的主要目的是通过回滚对象状态来实现撤消/重做操作,但是对于某些类型的游戏来说就足够了。

对于实时循环中的游戏,您可以将操作的每一帧都视为状态变化并进行存储。这是一种简单的实现方法。另一种方法是在对象状态更改时捕获。例如,检测何时改变作用在刚体上的力。如果您使用属性来获取和设置变量,那么这也可能是一个相对简单的实现,困难的部分是确定何时回滚状态,因为对于每个对象来说这都不是同一时间(您可以存储回滚时间(从系统开始算起的帧计数)。


0

在您的特殊情况下,通过倒带处理回滚应该可以正常工作。如果对AI单位使用任何形式的寻路,只需确保在回滚后重新计算它,以避免重叠的单位。

问题是您处理运动本身的方式:一个体面的物理引擎(一个2D上下射手很不错,一个非常简单的引擎)就可以跟踪过去的步伐信息(包括位置,净力等)坚实的基础。然后,确定最大回滚和回滚步骤的粒度,您应该获得所需的结果。


0

虽然这是一个有趣的想法。我不建议这样做。

向前播放游戏非常好,因为操作始终会对游戏状态产生相同的影响。这并不意味着反向操作会为您提供原始状态。例如,以任何编程语言评估以下表达式(关闭优化)

(1.1 + 3 - 3) == 1.1

至少在C和C ++中,它返回false。尽管差异可能很小,但请想象一下,在60fps的速度下,在10秒的几分钟内会累积多少错误。在某些情况下,玩家只会错过某些东西,而在游戏向后重播时会击中它。

我建议每半秒存储一次关键帧。这不会占用太多内存。然后,您可以在关键帧之间进行插值,甚至更好,可以模拟两个关键帧之间的时间,然后向后回放。

如果您的游戏不太复杂,只需每秒存储30次游戏状态的关键帧,然后向后播放即可。如果您有15个处于2D位置的对象,则不压缩就需要1.5分钟才能获得MB。计算机具有千兆字节的内存。

因此,不要过于复杂,向后重玩游戏并不容易,并且会导致很多错误。

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.