unity-editor-tools について
unity-editor-tools は、Unity のエディター拡張を作る開発者向けのスキルガイドです。カスタムインスペクターやウィンドウ、プロパティドロワーに加え、Scene View 操作や安全なエディタースクリプトのパターンを扱います。
主な機能
- 01カスタムインスペクターとエディターウィンドウ
- 02UI Toolkit と IMGUI の拡張
- 03プロパティドロワーとメニューコマンド
- 04Scene View の Handles と Gizmos
- 05SerializedObject による Undo と複数編集
- 06AssetDatabase のアセット操作
活用シーン
- 01コンポーネント専用インスペクターの構築
- 02ドッキング可能なツールウィンドウの作成
- 03Scene View でのオブジェクトプロパティ編集
- 04プロジェクトアセットの検索や管理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nice-wolf-studio/ unity-claude-skills --skill unity-editor-toolsインストール後、Claude Code で/unity-editor-toolsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/custom-inspectors.mdeditor-windows.mdproperty-drawers.md詳細
Unity エディターツール
エディタースクリプティングの概要
エディタースクリプトを使うと、カスタムインスペクター、ウィンドウ、ツール、ワークフローで Unity エディターを拡張できます。すべてのエディターコードは、Editor/ フォルダーに配置するか、#if UNITY_EDITOR / #endif で囲む必要があります。これにより、エディターコードがランタイムビルドから除外されます。
Unity 6.3 は、エディター拡張向けに 2 つの GUI フレームワークをサポートしています。
| フレームワーク | 状態 | エントリーポイント |
|---|---|---|
| UI Toolkit | 推奨 | CreateInspectorGUI() / CreateGUI() が VisualElement を返します |
| IMGUI | レガシーですが、完全に機能します | OnInspectorGUI() / OnGUI() |
主な基底クラス:Editor、EditorWindow、PropertyDrawer、DecoratorDrawer、ScriptableWizard。
カスタムインスペクター(Editor)
Editor を継承し、[CustomEditor(typeof(TargetType))] を適用します。詳しいガイドは references/custom-inspectors.md を参照してください。
UI Toolkit(推奨)
[CustomEditor(typeof(MyPlayer))]
public class MyPlayerEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
VisualElement root = new VisualElement();
var visualTree = Resources.Load("MyPlayerEditor") as VisualTreeAsset;
visualTree.CloneTree(root);
return root;
}
}
CreateInspectorGUI() をオーバーライドすると、OnInspectorGUI() は無視されます。
SerializedObject パターンを使った IMGUI
[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();
}
}
主なメンバー
| メンバー | 説明 |
|---|---|
target / targets | インスペクターで確認するオブジェクト |
serializedObject | 対象オブジェクトの SerializedObject |
DrawDefaultInspector() | 組み込みのデフォルトインスペクターを描画します |
OnSceneGUI() | Scene View に操作可能な Handles を描画します |
Scene View との連携
public void OnSceneGUI()
{
var t = (LookAtPoint)target;
EditorGUI.BeginChangeCheck();
Vector3 pos = Handles.PositionHandle(t.lookAtPoint, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Move look-at point");
t.lookAtPoint = pos;
}
}
PropertyDrawer と PropertyAttribute
シリアライズされたフィールドの Inspector 上での表示方法をカスタマイズします。詳しいガイドは references/property-drawers.md を参照してください。
1. 属性を定義する(ランタイムコード、Editor フォルダーの外):
public class MyRangeAttribute : PropertyAttribute
{
public readonly float min, max;
public MyRangeAttribute(float min, float max) { this.min = min; this.max = max; }
}
2. Drawer を実装する(Editor フォルダー):
[CustomPropertyDrawer(typeof(MyRangeAttribute))]
public class MyRangeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
MyRangeAttribute range = (MyRangeAttribute)attribute;
if (property.propertyType == SerializedPropertyType.Float)
EditorGUI.Slider(position, property, range.min, range.max, label);
else if (property.propertyType == SerializedPropertyType.Integer)
EditorGUI.IntSlider(position, property, (int)range.min, (int)range.max, label);
}
}
重要なルール: Editor/ フォルダーに配置する必要があります。EditorGUI(EditorGUILayout ではありません)を使います。プレハブのオーバーライドに対応するには、EditorGUI.BeginProperty() / EndProperty() を使用します。1 つの Drawer 内で UI Toolkit と IMGUI を併用することはできません。
EditorWindow
ドッキング可能なカスタムエディターウィンドウです。詳しいガイドは references/editor-windows.md を参照してください。
ライフサイクル: OnEnable -> CreateGUI -> Update -> OnGUI -> OnDisable
public class MyToolWindow : EditorWindow
{
[MenuItem("Tools/My Tool Window")]
public static void ShowWindow()
{
var window = GetWindow<MyToolWindow>();
window.titleContent = new GUIContent("My Tool");
window.minSize = new Vector2(300, 200);
}
public void CreateGUI()
{
rootVisualElement.Add(new Label("Hello from UI Toolkit!"));
rootVisualElement.Add(new Button(() => Debug.Log("Clicked!")) { text = "Click Me" });
}
}
| 静的メソッド | 説明 |
|---|---|
GetWindow<T>() | 既存のウィンドウを取得するか、新規作成します |
CreateWindow<T>() | 常に新しいインスタンスを作成します |
HasOpenInstances<T>() | 開いているかどうかを確認します |
| 表示モード | 動作 |
|---|---|
Show() | 標準のドッキング可能なウィンドウ |
ShowUtility() | フローティング表示、ドッキング不可 |
ShowModal() | モーダルダイアログ |
ShowAsDropDown() | ドロップダウンポップアップ |
MenuItem
[MenuItem] 属性を使うと、静的メソッドをメニューコマンドにできます。
[MenuItem("Menu/Path/Item Name", isValidateFunction, priority)]
| プレフィックス | 配置先 |
|---|---|
"Tools/..." | カスタムツールメニュー |
"Assets/..." | Assets メニューと Project のコンテキストメニュー |
"GameObject/..." | GameObject メニューと Hierarchy のコンテキストメニュー |
"CONTEXT/ComponentType/..." | コンポーネントのコンテキストメニュー |
ショートカット修飾キー: % = Cmd/Ctrl、# = Shift、& = Alt、^ = Ctrl(すべて)、_ = 修飾キーなし。
// Validation function controls when menu item is enabled
[MenuItem("Tools/Reset Position", true)]
static bool ValidateResetPosition() => Selection.activeTransform != null;
[MenuItem("Tools/Reset Position", false)]
static void ResetPosition()
{
Undo.RecordObject(Selection.activeTransform, "Reset Position");
Selection.activeTransform.position = Vector3.zero;
}
GameObject の作成(priority 10 を使用):
[MenuItem("GameObject/Custom/My Object", false, 10)]
static void CreateMyObject(MenuCommand menuCommand)
{
var go = new GameObject("My Object");
GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject);
Undo.RegisterCreatedObjectUndo(go, "Create My Object");
Selection.activeObject = go;
}
Gizmos と Handles
Gizmos -- Scene/Game View でのビジュアルデバッグ
すべての描画処理は OnDrawGizmos()(常時)または OnDrawGizmosSelected()(選択時)の内部で行います。
void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, radius);
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawSphere(transform.position, radius);
}
メソッド: DrawLine、DrawRay、DrawSphere、DrawWireSphere、DrawCube、DrawWireCube、DrawMesh、DrawWireMesh、DrawFrustum、DrawIcon。プロパティ: color、matrix。
Handles -- 3D 操作コントロール(エディター専用)
カスタム Editor の OnSceneGUI() 内で使用します。
[CustomEditor(typeof(CircleLayout))]
public class CircleLayoutEditor : Editor
{
public void OnSceneGUI()
{
var t = (CircleLayout)target;
Handles.color = new Color(1f, 0.8f, 0.4f, 1f);
Handles.DrawWireDisc(t.transform.position, t.transform.up, t.radius);
Handles.Label(t.transform.position, $"Radius: {t.radius:F1}");
EditorGUI.BeginChangeCheck();
float newRadius = Handles.RadiusHandle(Quaternion.identity, t.transform.position, t.radius);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(t, "Change Radius");
t.radius = newRadius;
}
}
}
メソッド: PositionHandle、RotationHandle、ScaleHandle、FreeMoveHandle、RadiusHandle、DrawLine、DrawWireDisc、Label、BeginGUI / EndGUI。プロパティ: color、matrix。
SerializedObject パターン
エディタースクリプトでプロパティを編集する標準的な方法です。Undo、複数オブジェクトの編集、Prefab オーバーライドの追跡を自動で提供します。
3 ステップのパターン:
serializedObject.Update(); // 1. Sync from target
EditorGUILayout.PropertyField(serializedObject.FindProperty("myField")); // 2. Draw/modify
serializedObject.ApplyModifiedProperties(); // 3. Apply with undo
| メンバー | 説明 |
|---|---|
Update() | ターゲットから更新 |
ApplyModifiedProperties() | Undo を含めて変更を適用 |
FindProperty(string) | 名前で SerializedProperty を取得 |
GetIterator() | すべてのプロパティを反復処理 |
targetObject / targetObjects | 検査対象のオブジェクト |
hasModifiedProperties | 適用されていない変更がある場合は True |
複数オブジェクトを編集するには、[CanEditMultipleObjects] を追加し、target ではなく必ず SerializedProperty を使用してください。
AssetDatabase
エディタースクリプトでアセットにプログラムからアクセスします。
// Create
var data = ScriptableObject.CreateInstance<MyData>();
AssetDatabase.CreateAsset(data, "Assets/Data/MyData.asset");
AssetDatabase.SaveAssets();
// Load
var loaded = AssetDatabase.LoadAssetAtPath<MyData>("Assets/Data/MyData.asset");
// Find by type
string[] guids = AssetDatabase.FindAssets("t:MyData");
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
var asset = AssetDatabase.LoadAssetAtPath<MyData>(path);
}
// Other operations
AssetDatabase.GetAssetPath(myObject);
AssetDatabase.DeleteAsset("Assets/Data/OldData.asset");
AssetDatabase.Refresh();
主なメソッド: CreateAsset、LoadAssetAtPath<T>、FindAssets、GetAssetPath、AssetPathToGUID/GUIDToAssetPath、SaveAssets、Refresh、DeleteAsset、CopyAsset、MoveAsset、RenameAsset、ImportAsset。
よく使われるパターン
// Editor-only guard
#if UNITY_EDITOR
using UnityEditor;
// editor code
#endif
// Change detection
EditorGUI.BeginChangeCheck();
// ... controls ...
if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(target, "Change"); }
// ScriptableObject creation menu
[CreateAssetMenu(fileName = "NewConfig", menuName = "Game/Config Data", order = 1)]
public class ConfigData : ScriptableObject { public float moveSpeed = 5f; }
// Default inspector + extras
[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (GUILayout.Button("Do Something")) { ((MyComponent)target).DoSomething(); }
}
}
アンチパターン
| アンチパターン | 問題 | 解決方法 |
|---|---|---|
Undo なしで target を編集する | Undo できず、ダーティーフラグも設定されない | SerializedObject または Undo.RecordObject() を使用する |
[CanEditMultipleObjects] と target を使用する | 最初のオブジェクトしか変更されない | SerializedProperty を使用する |
#if UNITY_EDITOR なしで Editor/ 外にエディターコードを置く | ビルドエラーが発生する | Editor/ フォルダーまたはプリプロセッサーガードを使用する |
PropertyDrawer で EditorGUILayout を使用する | サポートされていない | Rect と EditorGUI を使用する |
serializedObject.Update() の呼び出し漏れ | データが古くなる | 読み取る前に必ず呼び出す |
ApplyModifiedProperties() の呼び出し漏れ | 変更が失われる | 変更後に必ず呼び出す |
| 1 つの PropertyDrawer で UI Toolkit と IMGUI を混在させる | サポートされていない | いずれか 1 つのフレームワークを選ぶ |
Undo.RegisterCreatedObjectUndo() の呼び出し漏れ | 作成を Undo できない | 新しいオブジェクトを必ず登録する |
GameObjectUtility.SetParentAndAlign() の呼び出し漏れ | 親子階層が正しく設定されない | GameObject メニュー項目で使用する |
OnInspectorGUI()/OnGUI() で負荷の高い処理を行う | 遅延が発生する(フレームごとに何度も呼び出される) | OnEnable() でキャッシュする |
主要 API クイックリファレンス
Editor: [CustomEditor(typeof(T))], [CanEditMultipleObjects]
CreateInspectorGUI(), OnInspectorGUI(), OnSceneGUI()
DrawDefaultInspector(), target, targets, serializedObject
EditorWindow: GetWindow<T>(), CreateWindow<T>(), CreateGUI(), OnGUI()
rootVisualElement, titleContent, Show/ShowUtility/ShowModal
PropertyDrawer: [CustomPropertyDrawer(typeof(T))]
CreatePropertyGUI(), OnGUI(rect,prop,label), GetPropertyHeight()
attribute, fieldInfo, preferredLabel
SerializedObject: Update(), ApplyModifiedProperties(), FindProperty()
MenuItem: [MenuItem("Path", validate, priority)], % # & ^ _ shortcuts
Gizmos: DrawLine/Sphere/WireSphere/Cube/WireCube/Ray/Mesh/Icon, color, matrix
Handles: PositionHandle/RotationHandle/ScaleHandle/FreeMoveHandle/RadiusHandle
DrawLine/DrawWireDisc/Label, BeginGUI/EndGUI, color, matrix
AssetDatabase: CreateAsset, LoadAssetAtPath<T>, FindAssets, SaveAssets, Refresh
関連スキル
- unity-foundations -- プロジェクト構造、アセンブリ定義、Editor フォルダー
- unity-scripting -- MonoBehaviour のライフサイクル、SerializeField、ScriptableObject
- unity-ui -- UI Toolkit の基礎、VisualElement、UXML、USS