速習VRChatギミッカーのためのUnityEditor拡張

ユーザーがカスタマイズできるようなちょっと複雑なギミックを配布しようとするとPrefabをぽんと置くだけではセットアップできなくて困ることがよくあります。そんなときはUnityEditor拡張の出番です。UnityEditor拡張というと初めて使う人には何か難しそうなものに思えますが、実際には全然難しくないし、これほど便利なものはありません。UnityEditor拡張と一緒にギミックを配布すればユーザーはPrefabをぽんと置くのと同じか、それよりももっと簡単にギミックをセットアップできるようになります。やっていきましょう。

まずはEditorというディレクトリを作成してください。場所はどこでもかまいませんが、ギミックを配布しようとしているなら、そのギミックをパッケージにするときのRootのディレクトリがあるでしょうからその直下に作るのが良いでしょう。

f:id:sandman73773941:20210825000127p:plain

C#ソースファイルを作成します。

f:id:sandman73773941:20210825000158p:plain

using UnityEngine;
using UnityEditor;

class MyEditor : EditorWindow {
    [MenuItem("Window/My Window")]
    static void Init()
    {
        EditorWindow.GetWindow(typeof(MyEditor));
    }

    private void OnGUI()
    {
    }
};

これだけでWindowメニューにMyWindowという項目が表示されて、それを選択すると何もないWindowが出てきます。簡単ですね。

f:id:sandman73773941:20210825000238p:plain

f:id:sandman73773941:20210825000512p:plain

このままだと殺風景なので何か適当にGameObjectを受け取れるようにしましょう。

using UnityEngine;
using UnityEditor;

class MyEditor : EditorWindow
{
    public GameObject someObject; // <- 追加

    [MenuItem("Window/My Window")]
    static void Init()
    {
        EditorWindow.GetWindow(typeof(MyEditor));
    }

    private void OnGUI()
    {
        someObject = (GameObject)EditorGUILayout.ObjectField("SomeObject", someObject, typeof(GameObject), false); // <- 追加
    }
};

EditorGUILayout.ObjectFieldはObjectを取るフィールドを作成する関数ですが、floatを取りたいときはFloatField、stringを取りたいときはTextFieldが用意されています。

試しにCreateボタンを押したらSomeObjectのコピーをSceneに配置するようにしましょう。ボタンも簡単に追加できます。

using UnityEngine;
using UnityEditor;

class MyEditor : EditorWindow
{
    public GameObject someObject;
    public float floatValue = 3.14f;
    public string stringValue = "this is default value";

    [MenuItem("Window/My Window")]
    static void Init()
    {
        EditorWindow.GetWindow(typeof(MyEditor));
    }

    private void OnGUI()
    {
        someObject = (GameObject)EditorGUILayout.ObjectField("MySomeObject", someObject, typeof(GameObject), true);
        floatValue = EditorGUILayout.FloatField("MyFloatValue", floatValue);
        stringValue = EditorGUILayout.TextField("MyStringValue", stringValue);

        if (GUILayout.Button("Create")) // <- Createボタンを追加
        {
            GameObject createdObject = GameObject.Instantiate(someObject); // <- オブジェクトをコピーしてSceneに配置する
            createdObject.name = stringValue + floatValue.ToString(); // Fieldの値を元に名前を設定する
        }
    }
};

f:id:sandman73773941:20210825000341p:plain

これだけでかなりのことができるようになると思います。ボタン以外にも様々なUIコンポーネントが用意されているので探してみてください。

Fieldを増やしていくと入力した値がUnityを再起動するとリセットされるのが気になってきます。そういうときはScriptableObjectの出番です。

ScriptableObjectについてはそのうち追記するかも。