[Unity 程式] UnityEvent<T> 事件用法

發表日期:
2020.11.14
/
分類:
本文要說明的是在 Unity 中實作「事件」的程式 UnityEvent 基礎用法。

不管是 Delegate 還是 UnityEvent 都一樣,他們的用途主要是減少腳本之間依賴,在需要同時操作多個物件的開關、血量、目標時就不用在編輯器中的主腳本上關聯一大堆的物件,所以才有人說為遊戲加入 UnityEvent 就像飛起來一般。

在一切的開始,我們必須先做好 Using,請確保要進行宣告的腳本中有正確使用 UnityEngine.Events 命名空間。

using UnityEngine.Events;

不帶參數 No Parameter

大致上 UnityEvent 可以分成無參數和有參數兩種用法,特別是有參數的需要進行繼承,在這篇文章下半段會提到。

UnityEvent 最基礎、僅觸發不帶參數的方法的宣告如下:

public UnityEvent onCustomEvent = new UnityEvent();

以我的習慣來說會將他宣告在有實作 Singleton (單例模式) 的 Class 之下 (這邊的是實作成 ScriptableObject 版本),這樣就不用在編輯器中關聯一堆的物件,也無須用 FindObject… 之類的方法來佔效能。

Singleton 寫法有很多種,雖然概念都差不多。這邊附上我的寫法與應該宣告的位置:

using UnityEngine;
using UnityEngine.Events;

[CreateAssetMenu(menuName = "Custom/Storage")]
public class Storage : ScriptableObject
{
    private static Storage singleton;
    public static Storage Singleton
    {
        get
        {
            if (singleton == null)
            {
                singleton = CreateInstance<Storage>();
            }
            return singleton;
        }
    }
    public UnityEvent onCustomEvent = new UnityEvent();
}

那我們要如何讓其他腳本能加入 onCustomEvent 的監聽列表呢?因為我們現在有做好 Singleton,所以直接在 Awake 或建構式下直接調用 onCustomEvent 的 AddListener 即可。

using UnityEngine;

public class CustomObject : MonoBehaviour
{
    private void Awake()
    {
        Storage.Singleton.onCustomEvent.AddListener(PrintSomething);
    }
    private void PrintSomething()
    {
        Debug.Log("HAIYAA");
    }
}

AddListener 中直接帶入方法名稱就可以,但要注意的是這個 PrintSomething 方法不可以帶入任何參數,如果硬加上去是會報錯的。

最後在想要觸發 onCustomEvent 的地方進行 Invoke 就會執行啦!

private void Start()
{
    Storage.Singleton.onCustomEvent.Invoke();
}

如上圖,我在五個 CustomObject 中都加上了 CustomObject.cs,然後在 Controller 物件的腳本中的 Start 進行 Invoke。所以在遊戲一開始他就會印出五個 HAIYAA,不難理解吧?

同理可證,我複製十個就會有十個 HAIYAA,但作為呼叫端的 Controller 卻完全不需要進行物件引用,UnityEvent 真的是個很方便的東西。

有帶參數 Has Parameter

如果要讓他帶入參數,我們必須先弄一個新的 Class 並繼承 UnityEvent,寫法如下:

[System.Serializable]
public class CustomEvent : UnityEvent<bool> { }

那個 T 就是給你輸入要帶入的參數類型,如果要傳送的資料比較複雜,也可以使用自己寫的類別。這邊簡單示範用 bool 就好。

然後修改一下我們前面宣告的 onCustomEvent 類別,將他從 UnityEvent 改成新的 CustomEvent。

public CustomEvent onCustomEvent = new CustomEvent();

這樣子就能在 Invoke 中帶入參數了。

為了接收參數,我們要修改一下 CustomObject.cs 的內容:

using UnityEngine;

public class CustomObject : MonoBehaviour
{
    private void Awake()
    {
        Storage.Singleton.onCustomEvent.AddListener(PrintSomething);
    }
    private void PrintSomething(bool joy)
    {
        if (joy)
        {
            Debug.Log("HAIYAA");
        } else
        {
            Debug.Log("Ah shit, here we go again.");
        }
    }
}

小改成利用傳入的 joy 布林值來控制要印出什麼樣的字串。

最後在 Invoke 時直接帶入參數即可:

private void Start()
{
    Storage.Singleton.onCustomEvent.Invoke(true);
    Storage.Singleton.onCustomEvent.Invoke(false);
}

執行結果:

我對於 UnityEvent 和 Delegate 還是初學者程度,為了理解事件與委派的概念花了蠻多的時間,但這收穫我認為是超有幫助的。

學習真的是一件很棒的事情,真的要趁學生時段趕快學,出社會後真的就沒那麼多時間能這樣折騰了……

參考資料

comments powered by Disqus