mcpField
U
unity-editor-tools

unity-editor-tools

github.com/nice-wolf-studio开发4072 次安装6 周前更新
代码仓库

关于 unity-editor-tools

unity-editor-tools 是面向 Unity 开发者的编辑器扩展技能指南,涵盖自定义 Inspector、窗口、属性绘制器和菜单命令。内容也介绍场景视图交互、资源数据库及编辑器脚本的安全模式。

主要功能

  1. 01自定义 Inspector 与编辑器窗口
  2. 02UI Toolkit 和 IMGUI 扩展
  3. 03属性绘制器与菜单命令
  4. 04场景视图 Handles 和 Gizmos
  5. 05SerializedObject 撤销与多对象编辑
  6. 06AssetDatabase 资源操作

适用场景

  1. 01为组件构建专用 Inspector
  2. 02创建可停靠的编辑器工具窗口
  3. 03在场景视图中编辑对象属性
  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。所有编辑器代码都必须位于 Editor/ 文件夹中,或使用 #if UNITY_EDITOR / #endif 包裹,以确保编辑器代码会从运行时构建中剥离。

Unity 6.3 支持两种用于编辑器扩展的 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 视图中绘制可交互的 Handles
Scene 视图集成
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()。不能在同一个 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(使用优先级 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 视图中的可视化调试

所有绘制操作都在 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 模式

在编辑器脚本中编辑属性的标准方式。可自动支持撤销、多对象编辑和预制件覆盖跟踪。

三步模式:

serializedObject.Update();                                          // 1. Sync from target
EditorGUILayout.PropertyField(serializedObject.FindProperty("myField")); // 2. Draw/modify
serializedObject.ApplyModifiedProperties();                         // 3. Apply with undo
成员描述
Update()从目标对象刷新
ApplyModifiedProperties()提交更改并支持撤销
FindProperty(string)按名称获取 SerializedProperty
GetIterator()遍历所有属性
targetObject / targetObjects正在检查的对象
hasModifiedProperties存在尚未应用的更改时为 True

要进行多对象编辑:添加 [CanEditMultipleObjects],并始终使用 SerializedProperty,而不是 target。


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无法撤销,也不会标记为已修改使用 SerializedObject 或 Undo.RecordObject()
在 [CanEditMultipleObjects] 中使用 target只会修改第一个对象使用 SerializedProperty
在 Editor/ 外编写编辑器代码,且未使用 #if UNITY_EDITOR构建失败使用 Editor/ 文件夹或预处理器保护
在 PropertyDrawer 中使用 EditorGUILayout不受支持使用带 Rect 的 EditorGUI
缺少 serializedObject.Update()数据过时读取前务必调用
缺少 ApplyModifiedProperties()更改丢失修改后务必调用
在一个 PropertyDrawer 中混用 UI Toolkit 和 IMGUI不受支持选择一个框架
缺少 Undo.RegisterCreatedObjectUndo()无法撤销创建操作始终为新对象注册撤销
缺少 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

其他资源

评论

支持 Markdown