UnityでEdit ModeでスクリプトからUnityEventにリスナを登録して永続化する方法についてまとめました。
- やりたいこと
- 引数なしのメソッドを登録する
- 引数ありUnityEventに引数ありのメソッドを登録する
- 引数なしのUnityEventに引数ありのメソッドと引数を設定する
- 引数ありのUnityEventにプロパティを登録する
- UnityEventCallStateを切り替える
Unity2020.3.15f2
やりたいこと
UnityEventクラスをシリアライズするとInspectorから視覚的にこのイベントのリスナを登録できます。

このリスナはPlay ModeにおいてはUnityEvent.AddListener()を呼ぶだけで簡単に登録できますが、Edit Modeでは登録の仕方が若干複雑になります。
そこで本記事ではEdit Modeにおけるリスナの登録方法についてまとめます。
引数なしのメソッドを登録する
まず引数なしのメソッドを登録するには、以下のようにUnityEditor.Events.UnityEventTools.AddPersistentListener()を使用します。
using UnityEngine; using UnityEngine.Events; public sealed class UnityEventTest : MonoBehaviour { [SerializeField] private UnityEvent _event; public void Test() { } #if UNITY_EDITOR [UnityEditor.MenuItem("CONTEXT/UnityEventTest/AddEvent")] private static void AddEvent(UnityEditor.MenuCommand command) { var component = (UnityEventTest)command.context; UnityEditor.Events.UnityEventTools.AddPersistentListener(component._event, component.Test); } #endif }
このスクリプトを適当なGameObjectにアタッチしてContext MenuからAdd Eventを選択すると、リスナが登録されることを確認できます。

引数ありUnityEventに引数ありのメソッドを登録する
次に引数ありのUnityEventに引数ありのメソッドを登録する場合について考えます。
この場合には以下の例のように、前節と同じメソッドを使って登録できます。
using UnityEngine; using UnityEngine.Events; public sealed class UnityEventTest : MonoBehaviour { [SerializeField] private UnityEvent<int> _event; public void Test(int value) { } #if UNITY_EDITOR [UnityEditor.MenuItem("CONTEXT/UnityEventTest/AddEvent")] private static void AddEvent(UnityEditor.MenuCommand command) { var component = (UnityEventTest)command.context; UnityEditor.Events.UnityEventTools.AddPersistentListener(component._event, component.Test); } #endif }
Context MenuからAddEventを選択すると正常にリスナが登録されていることを確認できます。

引数なしのUnityEventに引数ありのメソッドと引数を設定する
次に引数なしのUnityEventに引数ありのメソッドを引数とともに登録する場合について考えます。
この場合には以下の例のように、UnityEditor.Events.UnityEventTools.AddIntPersistentListenerを使って登録できます。
using UnityEngine; using UnityEngine.Events; public sealed class UnityEventTest : MonoBehaviour { [SerializeField] private UnityEvent _event; public void Test(int value) { } #if UNITY_EDITOR [UnityEditor.MenuItem("CONTEXT/UnityEventTest/AddEvent")] private static void AddEvent(UnityEditor.MenuCommand command) { var component = (UnityEventTest)command.context; UnityEditor.Events.UnityEventTools.AddIntPersistentListener(component._event, component.Test, 123); } #endif }
登録結果は以下の通りとなります。

引数ありのUnityEventにプロパティを登録する
次に引数ありのUnityEventにプロパティを登録します。
これが少し厄介で、以下のようにプロパティのセッタのMethodInfoを取得して、それを呼ぶUnityActionを作る必要があります。
using System; using UnityEngine; using UnityEngine.Events; public sealed class UnityEventTest : MonoBehaviour { [SerializeField] private UnityEvent<int> _event; public int Test { get; set; } #if UNITY_EDITOR [UnityEditor.MenuItem("CONTEXT/UnityEventTest/AddEvent")] private static void AddEvent(UnityEditor.MenuCommand command) { var component = (UnityEventTest)command.context; // SetterのMethodInfoを取得 var setMethod = typeof(UnityEventTest).GetProperty("Test")?.GetSetMethod(); if (setMethod != null) { // Setterを呼ぶUnityActionを作成 var methodDelegate = (UnityAction<int>)Delegate.CreateDelegate(typeof(UnityAction<int>), component, setMethod); // リスナ登録 UnityEditor.Events.UnityEventTools.AddPersistentListener(component._event, methodDelegate); } } #endif }
リスナを登録した結果は以下の通りです。

UnityEventCallStateを切り替える
さてここまででリスナの登録は一通りできるようになったと思いますので、最後にUnityEventCallStateを切り替える方法について紹介します。
UnityEventCallStateとはつまり下図の部分のことです。

これをEdit Modeで切り替えるには以下のようにUnityEvent.SetPersistentListenerState()を使用します。
UnityEvent ev;
ev.SetPersistentListenerState(0, UnityEventCallState.EditorAndRuntime);