不管是 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 還是初學者程度,為了理解事件與委派的概念花了蠻多的時間,但這收穫我認為是超有幫助的。
學習真的是一件很棒的事情,真的要趁學生時段趕快學,出社會後真的就沒那麼多時間能這樣折騰了……