2017年1月24日 星期二

Unity裡的時間操作 - 倒帶

作者:Alexander Grishanin和Stas Korotaev
潤稿:Kelvin Lo

今天要介紹的遊戲是Lintrix
請多多支持購買願意分享開發經驗的好遊戲
Lintrix

獨立開發者總是同時身兼多職,今天我會繼續為大家更深入的探討,希望能對大家有幫助。

章節介紹:

  • 建立關卡
  • 時間倒帶
  • 遊戲設計應用(敬請期待)
  • 測試自動化(敬請期待)

在開發測試我們遊戲的過程中,我們發現因為玩家經常犯錯需要倒轉,因此需要在遊戲中做大量的記錄。事實上,我們遊戲的設計目的就是從各種方法來分散玩家的注意力,讓玩家因為分心導致遊戲失敗。所以我們想讓幫助玩家回想起曾今發生過甚麼事,比如顯示敵人的軌跡或在玩家之前死亡次數比較多的地方放個碰撞體。

有人擔心這樣做會讓螢幕變得混亂,或讓玩家容易重複之前的行為而不去思考新的方法,降低遊戲的趣味性。為了解決這個問題,我們發現利用時間軸功能來提示是個不錯的選擇。在每次遊戲失敗玩家點"重新開始"之後,我們可以
如圖所示用倒帶的方式重播回到起始點:


實現方法


事實上,幾乎所有重播要做的工作都在上一篇關卡建立所介紹的時間軸工具都完成了。但我們還不確定是否是最好的方案,所以我們先讓敵人和水晶的移動用相同方式回播。

雖然用之前的後退操作就能完成敵人和水晶的回播。但是關卡中有些事件是由玩家或者玩家的動作觸發的。所以我們需要為TimeManager加入新的接口:

public delegate void ReversingTimeActionDelegate();
public class TimeManager
{
    class ReversingActionWithTime
    {
       public float Time {get; set;}
       public ReversingTimeActionDelegate ActionToCarryOut {get; set;}
    }
    public void RememberAction(ReversingTimeActionDelegate action)
}
我們導入了ReversingActionWithTime這個類別來記錄動作的時間以及一個委託函式,它可以執行反向動作(類似程式設計裡的命令模式,但是透過與時間綁定而不是點ctrl+z或其他類似的複合鍵來觸發執行)。

當關卡執行且動作發生時,只需要把RememberAction反向函式加到這一時間,如果想讓時間倒退就可以呼叫這個函式。

例如,當有敵人碰到障礙消失時就加這個委託函式。之後如果點重新開始,回到這一時間點時,這個函式會再次啟動敵人的TimeManager呼叫,使敵人出現在螢幕上:

public class Enemy{
    void onCollisionWithBarrier()
    {
       timeManager.RememberAction(Activate);
       Deactivate();
    }
    void Activate()
    {
       // do the activation work
    }
    //.. Remaining implementation
}
在時間倒退模式時我們並不需要碰撞,因為這些碰撞已經在遊戲執行時就已經發生。所以只需要以更快的速度跳過一些幀來倒退遊戲狀態即可,不需要強大的硬體,倒退可以按照正常速度的20倍進行,而且關卡倒退完成就相當於重置所有的物件位置。

但在某些情況下還是需要將一些變數存在函數裡。例如下圖中黃色的子母彈(被消滅後會產生小敵人),它的位移需要被記錄下來,因為產生的小敵人軌跡會有1或2秒的隨機延遲。

右邊放那個紅點是有原因的,不是Bug XD

視覺與反饋


玩家非常喜歡時間倒退的感覺(特別是像晶體的大物件)。時間倒退不僅是一個視覺體驗,而且還能讓玩家再次回顧是如何敗給敵人的。這可以給玩家在遊戲開始前留一些思考時間,減少一些挫折感。

當玩家過關之後我們額外做了一件事。我們把介面切到遊戲地圖而非進入下一關,並重播你過關前的片段。


為了讓玩家有更好的倒帶視覺,我們做了些視覺處理。


例如在上圖我們把紅色的敵人凸顯出來,因為這是玩家需要看到的東西,這樣的視覺效果也很好。我們還加了時間倒轉的小圖示,雖然一開始我們想做類似VHS的倒帶效果,但後來因為不太符合視覺風格而作罷。這個效果是用灰階實現的,讓值大於0.7的紅色圖保持不變色。
範例下載:https://gist.github.com/Stals/b01487d44932a30be7d005870ab53798

另外,如果想要將這個效果用到鏡頭而非物件上,我們可以將著色器賦給某個材質,並將下面的腳本放到相機上:

using UnityEngine;
public class BasicPostEffect : MonoBehaviour
{
    [SerializeField]
    Material mat;
    void OnRenderImage(RenderTexture src, RenderTexture dst)
    {
        Graphics.Blit(src, dst, mat);
    }
}
接著,將新材質指給相機對應的欄位。

有趣的是,加了這個效果後,玩家不用重播就可以很清楚的知道關卡發生了哪些事情。同樣有趣的是,有部分玩家發現十次倒帶之後會出現一個從來沒看過的倒帶記憶

此外,我們還加入按兩下螢幕就能跳過倒帶的功能,按兩下螢幕也算是玩家想跳過時最常見的反應。

你還可以舉一反三嘗試一些不同用法。例如在遊戲中玩家失敗之後就秀出一些技巧說明,然後只倒帶一點時間讓玩家再次挑戰。這比讓整個關卡重新開始或行進間提示來的好。或是等玩家失敗幾次後才顯示提示。

我們也準備了一個簡單的範例專案,包含如何實現用TimeManager功能來記住物件行為。場景包含兩個方塊,當他們碰撞時會變色,由於有記錄它們的行為,因此在2.5秒後時間開始倒帶,顏色也會變回來。

專案下載

希望你已經有能力實現時間倒退的效果。下一篇文章我們會探討如何利用時間軸的遊戲設計,並瞭解如何解決一些常見的問題提升遊戲品質。

沒有留言:

張貼留言

關於我自己

我的相片
Unity台灣官方部落格 請上Facebook搜尋Unity Taiwan取得Unity中文的最新資訊