24
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Unity] カスタムエディタを使ってインスペクタをリッチにする

Last updated at Posted at 2016-07-30

Unityは通常のスクリプト以外にも、インスペクタを拡張する便利な機能がたくさんあります。
そのうちのひとつに「カスタムエディタ」があります。

エディタスクリプト全体についてはこちらにとても貴重な資料があるのでぜひ見てみてください。

基本形

カスタムエディタの基本的はこんな感じになります。
(ちなみに余談ですが、エディタスクリプトは Editor というディレクトリに保存します(ディレクトリの位置は任意))

AnyClassNameInspector.cs
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(AnyClassName))]
public class AnyClassNameInspector : Editor
{
    //
}

上記のように CustomEditor Attributeを利用し、 Editor クラスを継承したクラスを作成します。
こうすることによって、 typeof で渡されたクラスがインスペクタに表示される際に、このカスタムエディタクラスが適用され、自由にカスタマイズすることが可能になります。

インスペクタのGUIのカスタマイズ

インスペクタのGUIは OnInspectorGUI をオーバーライドすることでカスタマイズできます。
ごく簡単なサンプルは以下のようになります。

AnyClassNameInspector.cs
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(AnyClassName))]
public class AnyClassNameInspector : Editor
{
    AnyClassName anyClassName = null;
    
    void OnEnable()
    {
        // AnyClassNameコンポーネントを取得
        anyClassName = target as anyClassName;
    }
    
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        
        EditorGUILayout.LabelField("hoge", anyClassName.anyProperty.ToString());
    }
}

target プロパティが定義されており、そのプロパティに、 typeof で指定したクラスの参照が渡されます。
これを適切にキャストした上で、該当クラスのインスタンス変数から適宜、GUIに反映させていく、というのがおおまかな流れになります。

EditorGUIクラス

主に、インスペクタにGUIを表示するために利用するクラスです。
インスペクタを拡張する場合は必ず学習する必要があるクラスです。

UnityのUIを作るときに使用する GUI クラスのエディタ版、と考えると分かりやすいと思います。

EditorGUILayoutクラス

ドキュメントによると

EditorGUIの自動レイアウトバージョン

とのこと。

よく使いそうなもの

インスペクタのGUIを作る上で、よく使いそう or あとで思い出したくなりそうなものをざっくりメモ。

  • EditorGUILayout.ObjectField
    オブジェクトの参照を扱うフィールド。ドラッグ&ドロップで登録するいつものアレです。

ObjectFieldサンプル
↑こんな感じの。

EditorGUILayout.ObjectField(null, typeof(Object), false);
EditorGUILayout.ObjectField(null, typeof(GameObject), false);

// レイアウト情報付き
var options = new []{ GUILayout.Width(64), GUILayout.Height(64) };
EditorGUILayout.ObjectField(null, typeof(Texture), false, options);
  • EditorGUILayout.LabelField
    いわゆる「ラベル」。

上のと組み合わせるとこんな感じ。
ラベルサンプル

  • EditorGUILayout.HorizontalScope
    横方向のグルーピング。横に短い要素など、横方向に並べたほうがいいGUIを配置する際に利用する。使い方は以下の感じ。
using (new EditorGUILayout.HorizontalScope()) {
    EditorGUILayout.LabelField("any label");
    EditorGUILayout.LabelField("some label");
}

以上のような感じにすると using を利用した範囲において列挙したGUI要素が横方向にレイアウトされるようになります。

上のサンプルに適用するとこんな感じ。
レイアウトサンプル

  • EditorGUILayout.Popup
    いわゆるポップアップ型のUIを配置する。
    利用イメージはこんな感じ↓
public override void OnInspectorGUI()
{
    int index = 0;
    string[] list = new string[]{ "hoge", "fuga", "foo", "bar" };
    // `selectedIndex`には選択された新しいindexが格納される
    int selectedIndex = EditorGUILayout.Popup(index, list);
}

選択されたenumの値によって設定できるプロパティの表示を変更する

ありそうなケースとして、選択された enum の値に応じて、設定可能なプロパティを変更したい、ということがあると思います。
そんなときに使える設定方法(のメモ)。

public enum AnyType
{
    TypeA,
    TypeB,
    TypeC,
    TypeD,
}

public class AnyClass : MonoBehaviour
{
    [SerializeField]
    public AnyType AnyType;

    [SerializeField][HideInInspector]
    private string _anyName = "";

    [SerializeField][HideInInspector]
    private bool _anyBool = false;

    [SerializeField][HideInInspector]
    private Vector3 _anyVector = Vector3.zero;

    [SerializeField][HideInInspector]
    private float _anyFloat = 0f;

    // ... actual define.
}

#if UNITY_EDITOR
[CustomEditor(typeof(AnyClass))]
public class AnyClassInspector : Editor
{
    private AnyClass _target;
    private SerializedProperty _anyNameProperty;
    private SerializedProperty _anyBoolProperty;
    private SerializedProperty _anyFloatProperty;
    private SerializedProperty _anyVectorProperty;

    private void OnEnable()
    {
        _target = target as AnyClass;

        // 各種Propertyを取得する
        _anyNameProperty = serializedObject.FindProperty("_anyName");
        _anyBoolProperty = serializedObject.FindProperty("_anyBool");
        _anyFloatProperty = serializedObject.FindProperty("_anyFloat");
        _anyVectorProperty = serializedObject.FindProperty("_anyVector");
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        // シリアライズされたPropertyを更新しておく
        serializedObject.Update();

        switch (_target.AnyType)
        {
            case AnyType.TypeA:
                EditorGUILayout.PropertyField(_anyNameProperty);
                break;
            case AnyType.TypeB:
                EditorGUILayout.PropertyField(_anyNameProperty);
                EditorGUILayout.PropertyField(_anyBoolProperty);
                break;
            case AnyType.TypeC:
                EditorGUILayout.PropertyField(_anyNameProperty);
                EditorGUILayout.PropertyField(_anyFloatProperty);
                break;
            case AnyType.TypeD:
                EditorGUILayout.PropertyField(_anyNameProperty);
                _anyVectorProperty.vector3Value = EditorGUILayout.Vector3Field(_anyVectorProperty.displayName, _anyVectorProperty.vector3Value);
                break;
        }

        // 更新された値を適用する
        serializedObject.ApplyModifiedProperties();
    }
}
#end

覚えておくと便利そうなやつ

  • EditorGUIUtility
    1行の高さ、とか現在のビューのサイズ、とかの「それ知りたい」っていうのを提供してくれるクラス。

  • EditorGUI.indentLevel
    EditorGUIのインデントのレベル。
    整数なので EditorGUI.indentLevel++; とかすると、その次のレイアウトからインデントがひとつ増え、逆に -- するとインデントレベルがひとつ下がる、という感じで手軽に使える。

24
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?