时空幻境|如何实现时间倒流的魔法

前言


时空幻境是一款很有趣的独立游戏,游戏最大的一个特点是可以让时间倒流,回到前面的位置,灵活运用时间倒退的功能,触发各种机关,完成关卡。

关于时间倒流的思考


如何让游戏内的时间倒退,这是一个有趣的问题,在第一次这个游戏的时候,还是蛮震惊的,或许是第一次遇到这种类型的游戏,时间倒退的机制让人眼前一亮,当时并没有多想,现在从程序的角度思考,如何实现这一机制呢?

命令模式


使用命令模式来实现是一种可能的方法。

命令模式:将请求封装成对象,以便使用不同的请求、日志、队列等来参数化其他对象。命令模式也支持撤销操作。

定义看起来有些晦涩,其实并不难理解。在做游戏的时候,我们会将玩家的输入操作转换为游戏内的一个动作。比如按↑跳跃之类的。命令模式定义了一个Comand基类,而其他操作都会继承这个基类,并实现execute()和undo(),大概是这样的:

class Command {
public:
    //GameActor 是对应游戏中的“游戏对象”类
    virtual void execute(GameActor& actor) = 0;
    virtual void undo(GameActor& actor) = 0;
};

class JumpCommand : Command {
public:
    virtual void execute(GameActor& actor) {
        actor.jump();
    }
    virtual void undo(GameActor& actor) {
        actor.undoJump();
    }
};

这样我们就把游戏内对象的动作封装到了Command类中,控制一个角色就相当于执行一系列Command命令。这样做的好处是,我们可以记录用户的操作,把命令保存在一个stack中,当时间倒退的时候,只需要取出一个个Command命令,然后执行undo操作就可以了。

命令模式的好处是实现完各种命令以后,实现时间倒退,前进,加速减速就很简单了,只要不断执行execute或者undo就好了。缺点也很明显,这些命令并不好实现……

在时空幻境中,主角的动作其实比较少,只有跑跑跳跳,还是比较好实现的,但是也有很多其他的物体,这些物体也在运动,并可能与主角进行交互,所以如果用命令模式,实现起来还是相当复杂的。

备忘录模式


另一种方式比较暴力,就是备忘录模式,也就是保存游戏状态。

备忘录模式(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。

这个模式不用多说,就是每一帧将当前世界的状态做一个快照保存下来,然后当时间倒退的时候直接读取状态就好了。这种方法的好处就是:很好写,速度快。缺点当然就是比较耗费内存。

究竟有多么消耗内存呢?其实可以大概计算一下,假设一个关卡中有20个需要记录状态的游戏对象,每个对象大概需要6~7个属性(位置,移动速度和其他属性等,这里不太确定,不过我觉得需要的属性应该不多),出了位置以外,其他属性应该并不需要很高的精度,可以进行优化,不过这里还是先按照8个字节来算。那么游戏运行1个小时大概需要的内存就是:
一帧需要的内存 = 2068 = 960(byte)**
一秒如果设定为60帧,那么内存消耗 = 960 * 60 = 57600 (byte)
** 一个小时的内存消耗 = 57600 * 3600 / 1024 / 1024 = 197 (MB)**

接近200MB的消耗!这确实非常多,但是也并非不可行。还是有很多优化方案的,比如减少保存属性的字节。或者采用增量的保存方式,不是没帧都去保存所有值,而是保存改变值,这样会节省大量无效的内存,因为大部分时间,玩家可能是站在某个地方傻傻不动的。

利用上面的方法应该可以剩下一大半内存,另外,应该很少有人在一个章节玩一个小时,大概10~20分钟基本都可以完成了。实际上这个数字还算比较理想的了。

关于作者的帖子


本来到这里差不多结束了,不过我搜到了一个帖子:https://news.ycombinator.com/item?id=9484197

这个,大概是作者对于游戏机制实现的一些回答(从语气上看应该是吧),虽然英语很渣,不过大概可以看懂一些。

大概是说,作者大部分情况下记录了世界的状态,而不是记录事件(除了第五章)。实际上作者上述两个模式都有使用,并且表示使用命令模式非常令人烦躁,而且编写相反状态也非常复杂。

作者还表示,和与内存的消耗相比,CPU的消耗是更大的问题,所以他选择了使用保存状态的方法,在Xbox 360上,实际上在内存缓冲区消耗完之前,大概可以运行30-45分钟的样子。CPU消耗大应该是命令模式在需要执行命令很多的情况下可能会进行大量的计算,并且如果玩家进行加速操作,可能就更伤了。

另外,如果缓冲区被消耗完,那么就抛弃掉最开始的状态,这样虽然你并不能回到最初的状态,但是作者表示,好像并没有什么注意到这一点。

不知道有没有更好的实现方法,感觉其实都挺暴力的……

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容