時間回溯——用Unity實現時空幻境(Braid)中的控制時間效果

作者:QXYO

前言

控制時間相信幾乎是每個人都想擁有的能力,也為眾多影視、遊戲等提供了靈感,荒木老師在jojo的奇妙冒險中幾乎把控制時間的能力玩了個遍。而在遊戲領域,令筆者印象最深的就是本次的主角——時空幻境(Braid),一款把橫板跳躍與時間回溯完美結合的遊戲。

時間回溯——用Unity實現時空幻境(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)從場景中刪除。

時間回溯——用Unity實現時空幻境(Braid)中的控制時間效果

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上的,用於獲取和修改某一幀角色的動作;用於在時間倒流時暫停動畫的播放;,原工程的角色控制代碼,用於修改角色臉的朝向;,獲取、修改速度和時間倒流時關閉物理引擎。

void Start()

{

TimeBackData = new Stack();

SpriteRenderer = GetComponent();

animator = GetComponent();

cc2D = GetComponent();

m_Rigidbody2D = GetComponent();

}


首先是保存數據,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看看你的角色是不是已經是一個無敵的存在,畢竟一個可以無限時間倒流的人是不可能會輸的吧。(某平凡的上班族點了個贊!)

時間回溯——用Unity實現時空幻境(Braid)中的控制時間效果

如果追求細節的話能發現,時間回溯到在空中時結束回溯,角色會垂直落下,這時候只需要把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


分享到:


相關文章: