【第四章自定义编辑器窗口_扩展默认的编辑器窗口_扩展Hierarchy窗口(7/11)】
4.2 如何扩扩展默认的编辑器窗口
4.2.1 扩展Hierarchy窗口
using UnityEditor;
using UnityEngine;// 自定义Hierarchy窗口扩展类
public class CustomHierarchyWindow
{// InitializeOnLoadMethod特性表示这个方法在Unity编辑器启动或重新编译后自动执行[InitializeOnLoadMethod]static void InitializeOnLoad(){// 安全移除旧的事件监听器(防止重复注册)EditorApplication.hierarchyWindowItemOnGUI-= OnHierarchyWindowItemGUI;// 注册新的事件监听器EditorApplication.hierarchyWindowItemOnGUI+= OnHierarchyWindowItemGUI;}// Hierarchy窗口中每个项目的GUI绘制回调函数private static void OnHierarchyWindowItemGUI(int instanceID, // Unity对象的唯一实例IDRect selectionRect) // 当前项在Hierarchy窗口中的绘制矩形{// 通过实例ID查找对应的游戏对象GameObject go = EditorUtility.InstanceIDToObject(instanceID) as GameObject;// 如果找不到对应的游戏对象则退出if (go == null)return;// 获取该游戏对象上的所有组件Component[] components = go.GetComponents<Component>();// 遍历所有组件for (int i = 0; i < components.Length; i++){Component component = components[i];// 如果组件丢失(如脚本被删除),则跳过if (component == null)continue;// 获取组件的图标:// 1. 先尝试获取该类型的内置小图标// 2. 如果没有,则获取组件的缩略图Texture texture = AssetPreview.GetMiniTypeThumbnail(component.GetType()) ??AssetPreview.GetMiniThumbnail(component);// 如果没有可用的图标,则跳过if (texture == null)continue;// 计算图标位置(从Hierarchy项右侧从右向左排列)Rect rect = selectionRect;rect.x += selectionRect.width - (i + 1) * 20f; // 每个图标间隔20像素rect.width = 20f; // 图标宽度固定为20像素// 绘制组件图标并设置工具提示为组件类型名称GUI.Label(rect, new GUIContent(texture,component.GetType().Name));}}
}
代码功能详解
1. 初始化机制
[InitializeOnLoadMethod]
static void InitializeOnLoad()
{// 安全移除旧的事件监听(防止多次注册)EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyWindowItemGUI;// 注册新的事件监听EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyWindowItemGUI;
}
[InitializeOnLoadMethod]
特性:使方法在以下情况自动执行:- Unity 编辑器启动时
- 脚本重新编译后
- 事件注册:订阅
hierarchyWindowItemOnGUI
事件- 该事件在 Hierarchy 窗口绘制每个项目时触发
- 安全移除旧监听防止重复注册
2. 核心绘制函数
private static void OnHierarchyWindowItemGUI(int instanceID, // Unity内部对象标识符Rect selectionRect) // 当前项的矩形位置
{// 1. 从ID获取实际游戏对象GameObject go = EditorUtility.InstanceIDToObject(instanceID) as GameObject;// 2. 有效性检查if (go == null) return;// 3. 获取对象的所有组件Component[] components = go.GetComponents<Component>();// 4. 遍历所有组件for (int i = 0; i < components.Length; i++){Component component = components[i];// 跳过丢失的脚本(组件为空)if (component == null) continue;// 5. 获取组件图标(详见下文)Texture texture = GetComponentIcon(component);if (texture == null) continue;// 6. 计算位置并绘制图标Rect iconRect = CalculateIconRect(selectionRect, i);GUI.Label(iconRect, new GUIContent(texture, component.GetType().Name));}
}
3. 图标获取逻辑
Texture GetComponentIcon(Component component)
{// 1. 先获取类型专用图标(如Camera、Light等内置图标)Texture typeIcon = AssetPreview.GetMiniTypeThumbnail(component.GetType());// 2. 如果没有类型图标,获取组件的缩略图(自定义脚本图标)if (typeIcon == null) {typeIcon = AssetPreview.GetMiniThumbnail(component);}return typeIcon;
}
4. 图标位置计算
Rect CalculateIconRect(Rect baseRect, int index)
{Rect rect = baseRect;// 从右侧开始排列// - 20px * (index + 1) 确保从左向右顺序排列rect.x += baseRect.width - (index + 1) * 20f;// 固定宽度20像素rect.width = 20f;return rect;
}
5. 图标显示效果
在 Hierarchy 窗口中显示:
[游戏对象名称] [图标3] [图标2] [图标1]
- 图标顺序:组件添加顺序从右向左排列
- 悬停提示:鼠标悬停时显示组件类型名
- 自动跳过:
- 丢失的脚本(组件为null)
- 没有可用图标的组件
使用效果示例
场景中的显示效果:
用处
-
组件可视化:
- 直观展示对象上所有组件
- 无需展开查看Inspector
-
脚本丢失检测:
- 脚本丢失时图标不显示
- 快速发现损坏的对象
-
快速识别:
- 特殊图标表示特定组件
- 悬停提示显示具体类型名
-
顺序指示:
- 图标排列顺序反映组件添加顺序
- 帮助理解对象结构
使用注意事项
-
性能影响:
- 大型场景中可能会影响编辑器性能
- 建议添加显示对象数量阈值
-
兼容性:
- 只兼容 2018.3+ 版本的 Unity
- 旧版本 Unity 需要使用其他方法