ゲーム開発のスピードを向上させる鍵は、よく使うコンポーネント用にカスタムエディターを作成することです。ここで、ごく簡単なスクリプトの例を挙げましょう。このスクリプトでは、特定のオブジェクトが常に一定のポイントを向くようにしています。
//C# の例 (LookAtPoint.cs)
using UnityEngine;
public class LookAtPoint : MonoBehaviour
{
public Vector3 lookAtPoint = Vector3.zero;
void Update()
{
transform.LookAt(lookAtPoint);
}
}
これによって、オブジェクトが常にワールド空間の一点を向くようになります。現時点では、このスクリプトはプレイモードでのみ(つまりゲーム起動中にのみ)機能します。しかし、エディタースクリプトを書く場合、特定のスクリプトにはエディットモード(つまりゲームが起動していないとき)でも機能して欲しいことがあります。この設定は、属性 ExecuteInEditMode を追加することで行えます。
//C# の例 (LookAtPoint.cs)
using UnityEngine;
[ExecuteInEditMode]
public class LookAtPoint : MonoBehaviour
{
public Vector3 lookAtPoint = Vector3.zero;
void Update()
{
transform.LookAt(lookAtPoint);
}
}
上記によって、プレイモードでなくても、このスクリプトを持ったオブジェクトをエディター上で動かしたり、インスペクター上で “Look At Point” の値を変更したりすると、それに応じてオブジェクトの向きが変わるようになりました。つまり、オブジェクトが常にワールド空間の一定のポイントを向き続けるようになりました。
上記を参照すると、エディットタイムでの簡単なスクリプトの実行方法が分かります。しかしこれだけではユーザー独自のエディターツールの作成はできません。そこで、次のステップとして、今作成したスクリプト用に カスタムエディター を作成してみましょう。
Unity でスクリプトを作成すると、デフォルトでは MonoBehaviour から継承されるので Component となります。これはゲームオブジェクトに配置することができます。ゲームオブジェクトに配置されると、インスペクター上に、表示され得るすべてのパブリック変数(整数、浮動小数点数、文字列、Vector3 など)を表示、編集するためのデフォルトのインターフェースが表示されます。
上記のスクリプトは、デフォルトのインスペクターでは以下のように表示されます。
カスタムエディターは、このデフォルトレイアウトの 代わりに 任意のエディター制御を表示できるようにする、追加のスクリプトです。
LookAtPoint スクリプト用にカスタムエディターを作成するには、同じ名前に “Editor” という言葉を付け足した名前のスクリプトを、別にひとつ作成する必要があります。この参考例の場合は、名前は “LookAtPointEditor” となります。
//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 に伝えることができます。
OnInspectorGUI 内のコードは、Unity がインスペクター上でエディターを表示するたびに実行されます。ここにはどんな GUI コードでも入れることができます。ゲームに対して OnGUI と同じように機能しますが、こちらはインスペクターの中で実行されます。Editor は、インスペクトされているオブジェクトへのアクセスに使用できるターゲットプロパティーを定義します。カスタマイズしたインスペクターは以下のようになります。
ここまでに行ったのは、デフォルトのインスペクターの表示とまったく同様の Vector3 フィールドを再現することだけなので、結果の見た目もほとんど代わりません。(“Script” フィールドは、表示するためのインスペクターコードを加えなかったため、表示されていませんが。)
しかし、上記によってエディタースクリプト内でのインスペクターの表示を制御できるようになったので、好きなコードを使用して、インスペクターフィールドをレイアウトしたり、ユーザー自身が値を変更できるようにしたり、グラフィックスその他のビジュアル要素を表示させたりすることが可能になりました。Unity エディター内のインスペクターは、地形システムやアニメーション・インポート設定などの複雑なものも含め、すべて同じ 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)");
}
}
}
これで、ターゲットポイントがゲームオブジェクトの上にあるか下にあるか通知するための新しい要素が、インスペクターに加わりました。
これは、エディタースクリプトでできることのほんの一例にすぎません。すべての 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(EditorGUI 系)を配置したい場合は、Handles.BeginGUI() 前後で Handles.EndGUI() を呼び出す必要があります。
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.