Note: Unity エディター を拡張するには、UI Toolkit を使用することを強く推奨します。UI Toolkit は、IMGUI よりも最新の機能で、柔軟性があり、スケーラブルなソリューションを提供するからです。
アプリケーションの開発をスピードアップするために、よく使うコンポーネントのカスタムエディターを作成しましょう。このページでは、ゲームオブジェクトが常に一点を見るようにする簡単なスクリプトの作成方法を紹介します。
//C# の例 (LookAtPoint.cs)
using UnityEngine;
public class LookAtPoint : MonoBehaviour
{
public Vector3 lookAtPoint = Vector3.zero;
void Update()
{
transform.LookAt(lookAtPoint);
}
}
再生モードに入ると、スクリプトをアタッチしたゲームオブジェクトが、“Look At Point” プロパティに設定した座標に正面を向けます。エディタースクリプトを書くときに、アプリケーションが実行されていない 編集モード の間に、あるスクリプトを実行させたい場合があります。そのためには、以下のように ExecuteInEditMode
属性をクラスに加えます。
//C# の例 (LookAtPoint.cs)
using UnityEngine;
[ExecuteInEditMode]
public class LookAtPoint : MonoBehaviour
{
public Vector3 lookAtPoint = Vector3.zero;
void Update()
{
transform.LookAt(lookAtPoint);
}
}
これで、エディターでゲームオブジェクトを動かしたり、Inspector で “Look At Point” の値を変更したりすると、ゲームオブジェクトの回転が更新され、ワールド空間のターゲットポイントを見るようになります。
上記では、編集時に簡単なスクリプトを実行する方法を紹介しましたが、これだけでは独自のエディターツールを作成することはできません。次のステップでは、先ほど作成したスクリプト用に カスタムエディター を作成します。
Unity でスクリプトを作成すると、デフォルトで MonoBehaviour を継承しているのでコンポーネントとなり、ゲームオブジェクトにアタッチできます。コンポーネントをゲームオブジェクトに配置すると、Inspector にデフォルトのインターフェースが表示され、整数、浮動小数点、文字列などのパブリック変数を表示編集することができます。
LookAtPoint コンポーネントの Inspector は、デフォルトでは以下のようになっています。
カスタムエディターは追加のスクリプトで、このデフォルトレイアウトを選択した任意のエディター制御に置き換えます。
LookAtPoint スクリプト用のカスタムエディターを作成します。
//C# の例 (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
serializedObject.ApplyModifiedProperties();
}
}
このクラスは Editor クラスから派生している必要があります。CustomEditor 属性は、それがどのコンポーネントのエディターとして機能するべきかを Unity に伝えます。CanEditMultipleObjects 属性は、このエディターで複数のオブジェクトを選択し、同時に変更することを Unity に伝えます。
Unity が OnInspectorGUI のコードを実行すると、Inspector にエディターが表示されます。ここには任意の GUI コードを入れることができ、OnGUI と同じように動作しますが、Inspector の中で実行されます。エディターは、検証するゲームオブジェクトにアクセスするためのターゲットプロパティを定義します。
これは、LookAtPoint コンポーネントの Inspector が新しいエディターでどのように表示されるかを示しています。
これは非常によく似ていますが、“Script” フィールドは現在存在しません。なぜなら、エディタースクリプトにそれを表示するための Inspector コードが加えられていないためです。
上記によってエディタースクリプト内での Inspector の表示を制御できるようになったので、好きなコードを使用して、Inspector フィールドをレイアウトしたり、ユーザーが値を変更できるようにしたり、グラフィックスやその他のビジュアル要素を表示させたりすることが可能になりました。Unity エディター内に表示されるすべての Inspector は、Terrain (地形) システムやアニメーションインポート設定などの複雑なものも含め、同じ API で作られており、独自のカスタムエディターを作成する場合もこの API を使用することができます。
以下に簡単な例を挙げます。これは、ターゲットポイントがゲームオブジェクトの上にあるか下にあるかを示すメッセージが表示されるように、エディタースクリプトを拡張するものです。
//C# の例 (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
serializedObject.ApplyModifiedProperties();
if (lookAtPoint.vector3Value.y > (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Above this object)");
}
if (lookAtPoint.vector3Value.y < (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Below this object)");
}
}
}
LookAtPoint コンポーネントの Inspector に、ターゲットポイントがゲームオブジェクトの上か下かを示すメッセージが表示されている様子です。
エディターウィンドウ内でカメラを使ってシーンをレンダリングするなど、あらゆるタイプのインターフェースを描くために、すべての IMGUI コマンドにアクセスできます。
シーンビューに付加的なコードを加えることができます。これを行うには、カスタムエディターに OnSceneGUI を実装します。
OnSceneGUI はちょうど OnInspectorGUI と同じように機能しますが、シーンビュー内で実行されます。独自の編集コントロールを作成するために、Handles クラスで定義された関数を使用できます。この中にあるすべての関数は 3D シーンビューでの作業用に作られたものです。
//C#の例 (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
if (lookAtPoint.vector3Value.y > (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Above this object)");
}
if (lookAtPoint.vector3Value.y < (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Below this object)");
}
serializedObject.ApplyModifiedProperties();
}
public void OnSceneGUI()
{
var t = (target as LookAtPoint);
EditorGUI.BeginChangeCheck();
Vector3 pos = Handles.PositionHandle(t.lookAtPoint, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Move point");
t.lookAtPoint = pos;
t.Update();
}
}
}
3D 空間の中に 2D GUI オブジェクト (例えば、GUI や EditorGUI ) を加えたい場合は、Handles.BeginGUI() と Handles.EndGUI() の呼び出しでそれらをラップする必要があります。