Unityでスクリプトのメソッドを動的に呼び出す方法 - カスタムインスペクタと動的メソッド実行 -

Unityで、キー入力に応じて特定のスクリプトのメソッドを動的に呼び出したいと思ったことはありませんか？
この記事では、指定したキーを押したときに、任意のスクリプト内のメソッドを動的に実行できるようにする「GameManager」クラスと、その操作を簡単にするカスタムインスペクタについて解説します。

## 目的

通常、Unityではスクリプトのメソッドを直接呼び出すには、スクリプト内に対象のメソッド名を直接指定する必要があります。これでは実行するメソッド名が変わるたびにスクリプトを書き換える必要があります。

この記事では、Unityのエディタ拡張を活用して、インスペクタからスクリプトのメソッドを簡単に選択できるようにします。また、キー操作で動的に実行する仕組みを作成します。

## GitHub

https://github.com/yayoi-exe/unity-method-invoker

## GameManagerスクリプトの解説

最初に、メインとなる GameManager スクリプトを紹介します。
このスクリプトでは、指定したキーが押された際に、設定されたターゲットスクリプト内の指定されたメソッドを動的に実行します。

``` csharp
using UnityEngine;

public class GameManager : MonoBehaviour
{
    [SerializeField] private MonoBehaviour targetScript;
    [HideInInspector] public string selectedMethod;

    [SerializeField] private KeyCode activationKey = KeyCode.Space;

    // targetScriptを取得するためのプロパティ
    public MonoBehaviour TargetScript => targetScript;

    private bool _hasExperienceStarted = false;

    private void Update()
    {
        if (Input.GetKeyDown(activationKey) && !_hasExperienceStarted)
        {
            StartExperience();
        }
    }

    private void StartExperience()
    {
        _hasExperienceStarted = true;
        Debug.Log("Experience Started!");

        ExecuteTargetMethod();
    }

    private void ExecuteTargetMethod()
    {
        if (targetScript != null && !string.IsNullOrEmpty(selectedMethod))
        {
            var method = targetScript.GetType().GetMethod(selectedMethod);
            if (method != null)
            {
                method.Invoke(targetScript, null);
                Debug.Log($"Invoked {selectedMethod} on {targetScript.GetType().Name}");
            }
            else
            {
                Debug.LogError($"Method '{selectedMethod}' not found on script '{targetScript.GetType().Name}'");
            }
        }
        else
        {
            Debug.LogError("Please ensure the target script and method are properly set in the Inspector.");
        }
    }
}

```

## カスタムインスペクタでメソッドを選択できるようにする

次に、ターゲットスクリプトのメソッドをインスペクタで選択できるカスタムエディタを作成します。
これにより、Unityエディタ上でスクリプトを選択し、実行したいメソッドを簡単に指定できるようになります。

``` csharp
using UnityEditor;
using UnityEngine;
using System.Linq;
using System.Reflection;

[CustomEditor(typeof(GameManager))]
public class GameManagerEditor : Editor
{
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        GameManager gameManager = (GameManager)target;

        if (gameManager.TargetScript != null)
        {
            // ターゲットスクリプトの全てのメソッドを取得
            MethodInfo[] methods = gameManager.TargetScript.GetType()
                .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)
                .Where(m => m.GetParameters().Length == 0)  // 引数がないメソッドだけをリストにする
                .ToArray();

            // メソッド名のリストを作成
            string[] methodNames = methods.Select(m => m.Name).ToArray();

            // 現在選択されているメソッドをプルダウンで表示
            int selectedIndex = System.Array.IndexOf(methodNames, gameManager.selectedMethod);
            selectedIndex = EditorGUILayout.Popup("Select Method", selectedIndex, methodNames);

            // 選択したメソッドを更新
            if (selectedIndex >= 0 && selectedIndex < methodNames.Length)
            {
                gameManager.selectedMethod = methodNames[selectedIndex];
            }
        }
    }
}

```

## Unityでの使用方法

1. 任意のゲームオブジェクトにGameManagerコンポーネントをアタッチします
2. インスペクタ内で、Target Scriptフィールドに、実行したいスクリプト（MonoBehaviourを継承しているもの）をドラッグ＆ドロップします
3. Select Methodのドロップダウンメニューから、実行したいメソッドを選択します
    - メソッドは引数のないものだけが表示されます
4. Activation Keyにはメソッドを実行するためのキーを設定できます
    - デフォルトはスペースキーです
    - ゲームをプレイ中に指定したキーを押すと、選択したメソッドが実行されます

## おまけ：使い方や注意点

- 引数がないメソッドのみ対応:
    - このカスタムインスペクタでは、引数がないメソッドのみ選択可能です
    - 引数のあるメソッドには対応していませんが、リフレクションを応用すれば引数付きのメソッドにも対応できます
- メソッド名の確認:
    - メソッド名が間違っていたり、存在しなかった場合にはエラーログが出力されます

さらに応用して、メソッドに引数を渡す機能や、複数のキーで複数のメソッドを実行するような拡張も可能です