【Unity编辑器】EditorWindow的进阶应用与场景优化

张开发
2026/4/16 22:04:44 15 分钟阅读

分享文章

【Unity编辑器】EditorWindow的进阶应用与场景优化
1. EditorWindow的核心价值与基础搭建第一次接触Unity编辑器扩展时我被Scene窗口里那些可以自由拖拽的坐标轴吸引但真正让我效率翻倍的却是自定义EditorWindow。这就像给木匠打造专属工具箱——把每天重复的手动操作变成一键完成的智能按钮。创建基础窗口只需要三步新建继承EditorWindow的类、添加MenuItem标记、调用Show方法。但实际开发中我推荐更健壮的写法using UnityEditor; using UnityEngine; public class CustomToolkit : EditorWindow { [MenuItem(Tools/高级工具面板)] static void Init() { var window GetWindowCustomToolkit(); window.titleContent new GUIContent(效率工具, EditorGUIUtility.IconContent(d_Prefab Icon).image); window.minSize new Vector2(300, 400); window.Show(); } }这里有几个实用细节titleContent同时设置窗口标题和图标使用内置图标资源minSize避免窗口被缩得过小导致UI错乱使用Tools而非自定义菜单路径符合Unity官方规范2. 窗口事件的高级响应机制2.1 实时交互监听很多教程只教OnGUI绘制但实际项目更需要事件响应。比如我们需要在场景中选择物体时自动同步数据void OnSelectionChange() { if(Selection.activeGameObject ! null) { currentTarget Selection.activeGameObject; Repaint(); // 强制刷新UI } } void OnGUI() { if(currentTarget) { EditorGUILayout.LabelField($当前选中: {currentTarget.name}); } }这里有个坑要注意直接修改EditorWindow字段不会自动触发UI更新必须手动调用Repaint()。我曾在项目中因为忘记这个导致数据显示延迟排查了半天。2.2 智能场景响应做场景编辑器时常需要根据场景变化自动更新。比起每帧检测的笨办法更优雅的方式是void OnEnable() { EditorApplication.hierarchyChanged OnHierarchyChange; SceneView.duringSceneGui OnSceneGUI; } void OnDisable() { EditorApplication.hierarchyChanged - OnHierarchyChange; SceneView.duringSceneGui - OnSceneGUI; } void OnHierarchyChange() { // 当层级变化时执行新增/删除物体等 } void OnSceneGUI(SceneView sceneView) { // 实时响应场景视图操作 Handles.BeginGUI(); if(Event.current.type EventType.MouseDrag) { Debug.Log($鼠标拖动坐标{Event.current.mousePosition}); } Handles.EndGUI(); }这种事件订阅模式比老式的autoRepaintOnSceneChange更灵活还能减少不必要的性能开销。3. 专业级窗口布局技巧3.1 多面板协同工作复杂工具往往需要分栏设计比如材质编辑器那样的左右布局。通过EditorGUILayout.BeginHorizontal/EndHorizontal可以实现void OnGUI() { EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); // 左侧面板30%宽度 EditorGUILayout.BeginVertical(GUILayout.Width(position.width * 0.3f)); DrawObjectList(); EditorGUILayout.EndVertical(); // 右侧面板70%宽度 EditorGUILayout.BeginVertical(); DrawDetailInspector(); EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); }实际项目中我发现给每个区域添加GUILayout.ExpandHeight参数可以避免内容过多时的显示异常。3.2 智能停靠控制窗口停靠直接影响用户体验。通过如下代码可以检测窗口状态void OnGUI() { if(docked) { EditorGUILayout.HelpBox(窗口已停靠, MessageType.Info); if(GUILayout.Button(浮动窗口)) { this.SetDocked(false); } } else { if(GUILayout.Button(停靠到主窗口)) { var mainWindow EditorWindow.GetWindowSceneView(); this.AddTab(mainWindow); } } }这里有个隐藏技巧调用ShowTab方法可以实现类似Visual Studio的标签式窗口管理让多个工具窗口共享同一区域。4. 性能优化实战方案4.1 按需刷新机制EditorWindow默认每帧调用OnGUI这在复杂界面中会造成性能浪费。我的优化方案是private bool needRefresh; void Update() { // 只有标记为需要刷新时才重绘 if(needRefresh) { Repaint(); needRefresh false; } } void OnSelectionChange() { needRefresh true; // 外部事件触发刷新 }对于数据看板类工具可以结合EditorApplication.update实现定时刷新void OnEnable() { EditorApplication.update IntervalUpdate; } void IntervalUpdate() { if(Time.realtimeSinceStartup - lastUpdateTime 1.0f) { needRefresh true; lastUpdateTime Time.realtimeSinceStartup; } }4.2 资源加载优化工具窗口经常需要加载预览图等资源。错误示范是直接使用Resources.Load// 不推荐每次OnGUI都加载 var tex Resources.LoadTexture2D(icon);正确做法是在OnEnable预加载并在OnDisable释放private Texture2D cachedIcon; void OnEnable() { cachedIcon AssetDatabase.LoadAssetAtPathTexture2D( Assets/Editor/Icons/tool_icon.png); } void OnDisable() { if(cachedIcon ! null) { Resources.UnloadAsset(cachedIcon); } }在最近参与的MMO项目里通过这种优化使编辑器内存占用下降了40%。

更多文章