mcpField
U
unity-editor-tools

unity-editor-tools

github.com/nice-wolf-studio開発4072 回インストール6 週間前に更新
リポジトリ

unity-editor-tools について

unity-editor-tools は、Unity のエディター拡張を作る開発者向けのスキルガイドです。カスタムインスペクターやウィンドウ、プロパティドロワーに加え、Scene View 操作や安全なエディタースクリプトのパターンを扱います。

主な機能

  1. 01カスタムインスペクターとエディターウィンドウ
  2. 02UI Toolkit と IMGUI の拡張
  3. 03プロパティドロワーとメニューコマンド
  4. 04Scene View の Handles と Gizmos
  5. 05SerializedObject による Undo と複数編集
  6. 06AssetDatabase のアセット操作

活用シーン

  1. 01コンポーネント専用インスペクターの構築
  2. 02ドッキング可能なツールウィンドウの作成
  3. 03Scene View でのオブジェクトプロパティ編集
  4. 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.md
editor-windows.md
property-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

追加リソース

コメント