あらまし
開発中にデバッグメニューを作成時に機能を追加する度に
どのウィンドウに表示させるか決めて、表示名を決めて等の作業が面倒になる
そのため、フラグだけ建てておけば自動的に登録されていく機構があれば便利である
実装
メソッドに利用できる Attribute を作成し、
Awake時に それらのメソッドを利用できるように登録して管理する
メソッドに利用できる Attribute は以下のようになる
特に情報は必要無いので Attribute を継承しただけである
using System; [AttributeUsage(AttributeTargets.Method, Inherited = false)] public class InvokeMethodAttribute : Attribute { }
メソッドの管理を行うのが MethodObserver
である
Awake時に Register
、 Destroy時に Unset
を呼び出してもらう
実行するときは Invoke
を呼び出す
※特定のUnityVersionで GetCustomAttributes
で指定した CustomAttribute
を所持していない場合エラーになるので注意してください
using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEngine; using Object = System.Object; public static class MethodObserver { private static readonly Dictionary<Object, MethodInfo[]> dic = new Dictionary<Object, MethodInfo[]>(); /// <summary> /// 登録を解除 /// </summary> public static void Unset(Object obj) { if (!dic.ContainsKey(obj)) return; dic.Remove(obj); } /// <summary> /// メソッドを登録 /// </summary> public static void Register(Object obj) { var findMethods = obj.GetType() .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) .Where(m => m.GetCustomAttributes<InvokeMethodAttribute>(true).Any()).ToArray(); if (findMethods.Length <= 0) return; if (dic.ContainsKey(obj)) return; dic.Add(obj, findMethods); } /// <summary> /// メソッドを実行 /// </summary> public static void Invoke(Type type, string methodName, params Object[] paramerters) { var key = dic.Keys.First(o => o.GetType() == type); if (key == null) return; var method = dic[key].First(m => m.Name == methodName); method?.Invoke(key, paramerters); } }
メソッドを登録するための汎用的な MonoBehaviour
継承クラスが以下になる
using UnityEngine; public abstract class MethodBehaviourAbstract : MonoBehaviour { protected virtual void Awake() { MethodObserver.Register(this); } protected virtual void OnDestroy() { MethodObserver.Unset(this); } }
上記を継承したサンプルクラスが以下になる
このサンプルクラスであれば、SampleInvoke
が Awake 時に登録される
using UnityEngine; public class SampleMethodMonoBehaviour : MethodBehaviourAbstract { [InvokeMethod] private void SampleInvoke() { Debug.Log("Sample"); } private void Start() { MethodObserver.Invoke(GetType(), "SampleInvoke"); } }