Unityは通常のスクリプト以外にも、インスペクタを拡張する便利な機能がたくさんあります。
そのうちのひとつに「カスタムエディタ」があります。
エディタスクリプト全体についてはこちらにとても貴重な資料があるのでぜひ見てみてください。
基本形
カスタムエディタの基本的はこんな感じになります。
(ちなみに余談ですが、エディタスクリプトは Editor
というディレクトリに保存します(ディレクトリの位置は任意))
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(AnyClassName))]
public class AnyClassNameInspector : Editor
{
//
}
上記のように CustomEditor
Attributeを利用し、 Editor
クラスを継承したクラスを作成します。
こうすることによって、 typeof
で渡されたクラスがインスペクタに表示される際に、このカスタムエディタクラスが適用され、自由にカスタマイズすることが可能になります。
インスペクタのGUIのカスタマイズ
インスペクタのGUIは OnInspectorGUI
をオーバーライドすることでカスタマイズできます。
ごく簡単なサンプルは以下のようになります。
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
オブジェクトの参照を扱うフィールド。ドラッグ&ドロップで登録するいつものアレです。
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++;
とかすると、その次のレイアウトからインデントがひとつ増え、逆に--
するとインデントレベルがひとつ下がる、という感じで手軽に使える。