时间回溯——用Unity实现时空幻境(Braid)中的控制时间效果

时间回溯——用Unity实现时空幻境(Braid)中的控制时间效果

首页角色扮演时空幻境更新时间:2024-05-08
作者:QXYO前言

控制时间相信几乎是每个人都想拥有的能力,也为众多影视、游戏等提供了灵感,荒木老师在jojo的奇妙冒险中几乎把控制时间的能力玩了个遍。而在游戏领域,令笔者印象最深的就是本次的主角——时空幻境(Braid),一款把横板跳跃与时间回溯完美结合的游戏。

注意!由于本教程主要实现时间回溯效果,横板过关类游戏的场景搭建、移动、动画等不在本次内容范围内,有兴趣的同学可以先从B站专栏开始学起:
【简明UNITY教程】教你迅速实现2D角色的移动和跳跃:https://www.bilibili.com/video/BV1jJ41147WM

本次教程也会以该系列视频的工程为基础,在原项目上进行修改实现时间回溯的功能。

项目来源:【简明Unity教程】2D跳跃游戏的踩怪功能
https://www.bilibili.com/video/BV1v7411E7qz

基础工程:https://pan.baidu.com/share/init?surl=HISQizt0NvCHo8U0KgSCCA
提取码:jlbx

一、时间回溯实现原理

我们知道视频是能够倒放的,那游戏可不可以也像视频那样把每一帧记录下来,需要时再倒着输出实现时间倒流呢?答案当然是可以的,这种方法称为“备忘录模式”。事实上时空幻境的作者也说过该游戏主要是用该方法制作,有兴趣、英语好的同学可以看看作者的解释:
https://news.ycombinator.com/item?id=9484197

二、用Unity实现时间回溯

下载好前言中提到的基础工程,打开之后可能会有几个不影响的警告,Clear即可。打开Scene文件夹下的SampleScene场景,运行一下,试试操作人物移动、跳跃,应该不会有什么问题。

主要实现操控角色的时间倒流效果,所以先把怪物(opossum-1)从场景中删除。

1.设置保存数据类型

首先要确定每帧保存什么数据,位置数据、起跳后的速度数据,由于是2d动画所以还需要记录每帧所用的Sprite和脸的朝向。在Scripts文件夹里新建一个c#脚本,取名为ObjectStage。

public class ObjectStage

{

public Vector3 position { get; set; }

public Vector3 Velocity { get; set; }

public Sprite Sprite { get; set; }

public bool IsRight { get; set; }

}

2.保存角色状态

接下来就要实现时间倒流的效果了,新建脚本TimeBack挂到Player上。由于读取数据是从后往前读取,所以可以使用stack(栈)一个后进先出的容器来保存数据。同时也需要获取到player上的<SpriteRenderer>,用于获取和修改某一帧角色的动作;<Animator>用于在时间倒流时暂停动画的播放;<CharacterController2D>,原工程的角色控制代码,用于修改角色脸的朝向;<Rigidbody2D>,获取、修改速度和时间倒流时关闭物理引擎。

void Start()

{

TimeBackData = new Stack();

SpriteRenderer = GetComponent<SpriteRenderer>();

animator = GetComponent<Animator>();

cc2D = GetComponent<CharacterController2D>();

m_Rigidbody2D = GetComponent<Rigidbody2D>();

}

首先是保存数据,cc2D.m_FacingRight在原工程里受保护的(private)这里我们需要公开(public)。

void SaveData()

{

ObjectStage stage = new ObjectStage();

stage.Position = transform.position;

stage.Sprite = SpriteRenderer.sprite;

stage.IsRight = cc2D.m_FacingRight;

stage.Velocity = m_Rigidbody2D.velocity;

TimeBackData.Push(stage);

}

3.读取和显示状态

接下来是读取数据,读取后的数据就可以删除了,可以用Stack.Pop(),但是最后一个读取的数据,也就是第一个保存的数据不能删,可以用 Stack.Peek()。

ObjectStage LoadData()

{

if (TimeBackData.Count > 1)

{

return (ObjectStage)TimeBackData.Pop();

}

else

{

return (ObjectStage)TimeBackData.Peek();

}

}

然后就是把读取的数据反映到Player身上,也就是时间倒流的过程,要注意在这期间角色应该是不受物理引擎的影响,并且不能播放动画,要在代码中关闭。

void ShowData(ObjectStage stage)

{

animator.enabled = false;

transform.position = stage.Position;

SpriteRenderer.sprite = stage.Sprite;

transform.localScale = new Vector3(stage.IsRight ? 1 : -1, 1, 1);

m_Rigidbody2D.simulated = false;

m_Rigidbody2D.velocity = stage.Velocity;

}

4.调用代码实现时间回溯

方法写好了,接下来就是调用了,我们知道update在一秒内执行的次数是不固定的,所以我们保存数据和读取数据只能放在FixedUpdate里。并且只有在按下时间倒流的按键时才能读取数据,其他时间保存数据,按键抬起的时候要把之前关闭的物理引擎和动画开启。

ObjectStage LoadStageData = new ObjectStage();

private void FixedUpdate()

{

if (CheckKey)

{

LoadStageData = LoadData();

if (LoadStageData != null)

{

ShowData(LoadStageData);

}

}

else

{

SaveData();

}

}

(注意,按键检测仍然要放在UpDate里。)

private void Update()

{

CheckKey = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);

CheckKeyUp = Input.GetKeyUp(KeyCode.LeftShift) || Input.GetKeyUp(KeyCode.RightShift);

if (CheckKeyUp)

{

cc2D.m_FacingRight = LoadStageData.IsRight;

animator.enabled = true;

m_Rigidbody2D.simulated = true;

}

}

运行游戏操作一会,再按下Shift看看你的角色是不是已经是一个无敌的存在,毕竟一个可以无限时间倒流的人是不可能会输的吧。(某平凡的上班族点了个赞!)

如果追求细节的话能发现,时间回溯到在空中时结束回溯,角色会垂直落下,这时候只需要把CharacterController2D脚本上的canAirControl勾选为false即可继续跳跃。但这样修改也有个问题,角色不能在空中移动了,为了模拟Braid原版游戏的手感,我们可以尝试修改基础工程的move方法。

首先把canAirControl勾选为false。

if (m_Grounded || canAirControl)

{

// 输入变量move决定横向速度

m_Rigidbody2D.velocity = new Vector2(move, m_Rigidbody2D.velocity.y);

}

else if (!m_Grounded)

{

if (move > 0 && m_FacingRight)

{

m_Rigidbody2D.velocity = new Vector2(Mathf.Max(move, m_Rigidbody2D.velocity.x), m_Rigidbody2D.velocity.y);

}

else if (move < 0 && !m_FacingRight)

{

m_Rigidbody2D.velocity = new Vector2(Mathf.Min(move, m_Rigidbody2D.velocity.x), m_Rigidbody2D.velocity.y);

}//如果在空中有相反方向的操作则修改水平速度

}

修改后的手感就和Braid里面非常相似了。

另外,如果想在时间回溯时音频也跟着倒放,可以修改AudioSource组件的Pitch参数为-1。

修改后的工程:

https://pan.baidu.com/share/init?surl=tmPDt9Ebq814cbasffOhlA

提取码: m4pg


对线下游戏开发学习感兴趣的盆友,欢迎访问:http://levelpp.com/

同时,也欢迎加入游戏开发群搅基:610475807

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved