Unity引擎编辑器架构详解
一、编辑器架构总览
Unity编辑器(Unity Editor)是基于C++和C#混合开发的可视化内容创作环境。其架构大致分为三层:
-
底层引擎(C++)
- 负责资源导入、场景渲染、物理、动画、底层API等。
- 提供C# API的底层实现。
-
编辑器核心(C#)
- 负责Inspector、Hierarchy、Project、Scene等窗口的逻辑。
- 提供编辑器扩展API(UnityEditor命名空间)。
- 管理资源、场景、组件、序列化、Undo/Redo等。
-
用户扩展层(C#)
- 用户可通过Editor脚本自定义窗口、工具、菜单、Inspector、资源导入流程等。
- 支持自定义Gizmos、绘制Scene视图、批量处理资源等。
二、核心组成模块
1. 编辑器窗口系统(EditorWindow)
- 所有编辑器窗口(如Inspector、Project、Scene、Console)都继承自
EditorWindow
。 - 支持自定义窗口、布局、Dock、弹窗等。
- 通过
[MenuItem]
注册菜单,EditorWindow.GetWindow<T>()
创建窗口。
2. Inspector与PropertyDrawer
- Inspector用于显示和编辑选中对象的属性。
- 支持自定义Inspector(
Editor
类)、自定义属性绘制(PropertyDrawer
)。 - 支持序列化字段、Undo/Redo、Prefab变体等。
3. Scene视图与Gizmos
- Scene视图用于可视化编辑场景对象。
- 支持自定义Gizmos、Handles、Scene GUI交互。
- 可通过
OnSceneGUI
扩展Scene视图的交互。
4. 资源导入与Asset Pipeline
- 资源导入流程由Asset Pipeline管理,支持自定义Importer、Processor。
- 支持AssetDatabase、GUID、依赖追踪、增量导入。
- 支持ScriptedImporter自定义任意格式资源导入。
5. 菜单与快捷键
- 通过
[MenuItem]
添加菜单项、右键菜单、快捷键。 - 支持上下文菜单、批量操作。
6. 编辑器事件与回调
- 支持Selection、Undo、HierarchyChanged、ProjectChanged等事件。
- 支持EditorApplication、EditorUtility等全局API。
三、底层原理与运行时关系
- 编辑器与运行时共享大部分C# API,但编辑器专属API在
UnityEditor
命名空间,仅在编辑器下可用。 - 编辑器脚本不会被打包进最终游戏(除非用
[ExecuteInEditMode]
等特殊方式)。 - 编辑器通过反射、序列化、消息分发等机制实现灵活扩展。
四、扩展机制与常用API
1. 自定义窗口
using UnityEditor;
using UnityEngine;
public class MyWindow : EditorWindow
{
[MenuItem("Window/My Custom Window")]
public static void ShowWindow()
{
GetWindow<MyWindow>("My Window");
}
void OnGUI()
{
GUILayout.Label("Hello Editor!", EditorStyles.boldLabel);
}
}
2. 自定义Inspector
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (GUILayout.Button("Do Something"))
{
((MyComponent)target).DoSomething();
}
}
}
3. 自定义资源导入
using UnityEditor;
using UnityEngine;
public class MyTextureProcessor : AssetPostprocessor
{
void OnPreprocessTexture()
{
TextureImporter importer = (TextureImporter)assetImporter;
importer.mipmapEnabled = false;
}
}
4. Scene视图扩展
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : Editor
{
void OnSceneGUI()
{
MyComponent comp = (MyComponent)target;
Handles.Label(comp.transform.position, "Hello Scene!");
}
}
五、编辑器开发最佳实践
- 分层设计:将编辑器代码与运行时代码分离,使用
Editor
文件夹。 - Undo/Redo支持:所有编辑器操作应支持撤销(
Undo.RecordObject
)。 - 序列化兼容:使用
SerializedObject
和SerializedProperty
,兼容Prefab、Multi-Edit等。 - 性能优化:避免在
OnGUI
中频繁分配内存,合理使用缓存。 - 批量处理:利用
AssetDatabase
、Selection
等API批量处理资源。 - 可视化与交互:善用Gizmos、Handles、EditorGUILayout提升工具易用性。
- 自动化:结合MenuItem、脚本批处理、资源导入自动化等提升效率。
六、常见编辑器扩展场景
- 批量资源重命名、格式转换、自动分组
- 自定义场景工具(如地形编辑、路径编辑、关卡布置)
- 资源依赖分析、冗余检测
- 游戏数据可视化编辑器(如技能树、对话编辑器、关卡编辑器)
- 自动化构建、打包、热更工具
- 运行时调试辅助工具(如日志面板、内存监控)
七、架构图(简化示意)
+-------------------+
| Unity Editor |
|-------------------|
| EditorWindow |<--自定义窗口
| Inspector |<--自定义Inspector/Drawer
| SceneView |<--Gizmos/Handles
| Asset Pipeline |<--Importer/Processor
| Menu/Shortcut |<--MenuItem/ContextMenu
| Editor Events |<--Selection/Undo/Callback
+-------------------+
|
v
+-------------------+
| Unity Engine |
| (C++/C# Runtime) |
+-------------------+
八、参考文档
下面将继续深入,补充Unity编辑器架构的底层机制、序列化系统、消息与事件流、扩展进阶、自动化与批处理、性能优化、常见陷阱与实战建议等内容。
一、底层机制与序列化系统
1. Unity序列化系统
- Unity编辑器依赖自有的序列化系统(非C#标准序列化),用于Inspector显示、Prefab、Undo/Redo、资源存储等。
- 支持的类型:基本类型、UnityEngine.Object、Serializable类、List/Array、部分Dictionary。
- 不支持的类型:泛型类、接口、委托、非public字段(除非加[SerializedField])、多维数组等。
- 编辑器通过
SerializedObject
和SerializedProperty
反射式访问和绘制字段,保证多选、Prefab变体等一致性。
2. Undo/Redo机制
- 编辑器所有可变更操作应支持Undo/Redo。
- 通过
Undo.RecordObject
、Undo.RegisterCreatedObjectUndo
等API记录状态。 - Inspector、SceneView、资源导入等都应配合Undo系统,避免数据丢失。
3. 编辑器与运行时的隔离
- 编辑器代码必须放在
Editor
文件夹下,打包时不会包含。 - 运行时代码可通过
#if UNITY_EDITOR
条件编译访问编辑器API,但要避免依赖。
二、消息与事件流
1. 编辑器生命周期
- 编辑器窗口、Inspector、SceneView等都基于IMGUI(Immediate Mode GUI)系统,核心方法为
OnGUI
。 - 编辑器事件流包括:Awake/OnEnable/OnDisable/OnDestroy、OnGUI、OnInspectorGUI、OnSceneGUI等。
- 编辑器全局事件:
EditorApplication.update
(每帧)、EditorApplication.playModeStateChanged
、Selection.selectionChanged
等。
2. 资源导入与回调
- 资源导入流程:导入(Importer)→ 处理(Processor)→ 存储(AssetDatabase)。
- 支持
AssetPostprocessor
、ScriptedImporter
自定义导入逻辑。 - 资源变更、导入、删除等事件可通过
AssetModificationProcessor
、AssetDatabase
监听。
三、扩展进阶
1. 自定义PropertyDrawer与DecoratorDrawer
PropertyDrawer
:自定义字段在Inspector的绘制方式(如Vector3、Color等)。DecoratorDrawer
:为字段添加装饰(如Header、Space等)。- 支持自定义Attribute,提升Inspector可读性和交互性。
2. Editor Coroutines(编辑器协程)
- 编辑器原生不支持协程,但可用
EditorApplication.update
模拟。 - 适合做批量处理、异步任务、进度条等。
3. 编辑器工具链自动化
- 利用
MenuItem
、AssetDatabase
、BuildPipeline
等API实现一键打包、资源检查、自动化构建。 - 可结合CI/CD(如Jenkins、GitHub Actions)实现自动化流程。
四、性能优化与常见陷阱
1. 性能优化
- 避免在
OnGUI
/OnInspectorGUI
中频繁分配内存或做重计算。 - 使用缓存、延迟加载、脏标记(Repaint/SetDirty)等手段。
- 批量操作时,使用
AssetDatabase.StartAssetEditing/StopAssetEditing
减少刷新次数。
2. 常见陷阱
- 内存泄漏:未正确释放EditorWindow、未移除事件监听。
- Undo失效:未调用Undo API,导致操作无法撤销。
- 序列化丢失:字段未标记为可序列化,数据无法保存。
- 多选兼容性:自定义Inspector未用
SerializedProperty
,多选时数据错乱。 - 资源锁死:批量处理资源时未正确结束编辑,导致资源锁定。
五、实用进阶代码片段
1. 编辑器协程
public static class EditorCoroutine
{
public static IEnumerator Start(IEnumerator routine)
{
void Update()
{
if (!routine.MoveNext())
EditorApplication.update -= Update;
}
EditorApplication.update += Update;
return routine;
}
}
2. 批量资源处理
[MenuItem("Tools/Batch Rename")]
public static void BatchRename()
{
var guids = Selection.assetGUIDs;
AssetDatabase.StartAssetEditing();
try
{
foreach (var guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
AssetDatabase.RenameAsset(path, "NewName_" + Path.GetFileNameWithoutExtension(path));
}
}
finally
{
AssetDatabase.StopAssetEditing();
AssetDatabase.Refresh();
}
}
3. 自定义属性与Drawer
public class ReadOnlyAttribute : PropertyAttribute { }
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
public class ReadOnlyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
GUI.enabled = false;
EditorGUI.PropertyField(position, property, label);
GUI.enabled = true;
}
}
六、实战建议
- 工具分层:复杂工具建议拆分为数据层、逻辑层、UI层,便于维护。
- 可视化交互:多用Handles、Gizmos提升场景工具体验。
- 批量与自动化:一切重复性工作都应自动化,提升团队效率。
- 文档与注释:编辑器工具需良好注释和使用说明,方便团队协作。
- 测试与回退:编辑器工具易出错,建议配合版本控制、Undo、日志等机制。
七、常见编辑器扩展案例
- 关卡编辑器:自定义窗口+SceneView交互+数据序列化
- 技能/对话树编辑器:节点式可视化+批量数据导入导出
- 资源检查工具:批量扫描、依赖分析、冗余检测
- 自动化打包工具:一键构建、分包、热更、日志输出
- 运行时调试面板:编辑器下可视化运行时数据、日志、性能