topaz-dev’s

ああああああ

Unity エディタ拡張 インスペクターから関数を実行するボタンの作成

インスペクターからスクリプト内の関数を実行できるボタンを作成しました。


www.youtube.com

目的

今回目指した内容はスクリプト独自のエディタ拡張を書かずに、スクリプトに簡単な記載をすることでスクリプト内の関数を実行ですることができるボタンを作成すること。とはいえ、Inspecctorにボタンを表示するために表示するための変数が必要だった。ActionButton構造体を作成してスクリプトの変数にすることでボタンの作成を行なった。
以下のTestScriptを当たってして、定義されてある関数の実行を行なった例が上の動画である。

// TestScript.cs
using UnityEngine;
public class TestScript : MonoBehaviour
{
    // 関数を実行するボタン。
    public ActionButton _actionButton;
    public void HelloWorld()
    {
        Debug.Log("HelloWorld");
    }
    private void SayGoodBye()
    {
        Debug.Log("Good Bye");
    }
    [SerializeField] int _myIntValue;
    private void ShowMyIntValue()
    {
        Debug.Log($"myIntValue : {_myIntValue}");
    }
}
ActionButton

今回作成したコード。ActionButtonの構造体は一つ変数を定義しているが実際には使用されておらず、描画エリア確保のために定義してある。実際にメソッドを取得したりするコードはActionButtonEditorに書かれている。

// ActionButton.cs
using UnityEngine;
using UnityEditor;
using System.Linq;
using System.Reflection;

[System.Serializable]
public struct ActionButton
{
    // 実際には使われていないダミープロパティ
    public bool IsActive;
}

[CustomPropertyDrawer(typeof(ActionButton))]
public class ActionButtonEditor : PropertyDrawer
{
    private int _methodIndex = 0;
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var objectReferenceValue = property.serializedObject.targetObject;
        var type = objectReferenceValue.GetType();
        var bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

        // 関数を取得する
        var methods = type.GetMethods(bindingAttr);

        // Unityのデフォルトで実装指されている関数を表示しないようにする
        var methodNames = methods
                .Where(a => a.MethodImplementationFlags == MethodImplAttributes.Managed)
                .Where(a => a.Module.Name != "UnityEngine.CoreModule.dll")
                .Select(a => a.Name)
                .ToArray<string>();

        // 左側に関数選択のポップアップを表示。右側に実行ボタンの表示
        position.width -= 70;
        _methodIndex = EditorGUI.Popup(position, _methodIndex, methodNames);
        var method = type.GetMethod(methodNames[_methodIndex], bindingAttr);
        position.x = position.x + position.width + 10;
        position.width = 60;
        if (method != null)
        {
            if (GUI.Button(position, "実行"))
            {
                method.Invoke(objectReferenceValue, null);
            }
        }
        else
        {
            GUI.Label(position, "実行できない関数です");
        }
    }
    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUIUtility.singleLineHeight;
    }
}


まとめ

参考サイトにとても助けられました。指定した関数をすぐにエディタで実行できるようになり開発効率があがると嬉しいです。
特に関数を追加した際に自動的にポップアップに追加されるのでいろいろなところに配置できるかな。今度は関数の引数も指定して実行できるようにできたらと思います。

参考サイト

【Unity】Inspector に指定された関数を実行するボタンを表示する PropertyDrawer - コガネブログ