【第四章自定义编辑器窗口_扩展默认的编辑器窗口_扩展Hierarchy窗口(8/11)】

4.2 如何扩扩展默认的编辑器窗口

4.2.1 扩展Hierarchy窗口

csharp 复制代码
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对象的唯一实例ID
        Rect 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. 初始化机制

csharp 复制代码
[InitializeOnLoadMethod]
static void InitializeOnLoad()
{
    // 安全移除旧的事件监听(防止多次注册)
    EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyWindowItemGUI;
    
    // 注册新的事件监听
    EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyWindowItemGUI;
}
  • [InitializeOnLoadMethod] 特性 :使方法在以下情况自动执行:
    • Unity 编辑器启动时
    • 脚本重新编译后
  • 事件注册 :订阅 hierarchyWindowItemOnGUI 事件
    • 该事件在 Hierarchy 窗口绘制每个项目时触发
    • 安全移除旧监听防止重复注册

2. 核心绘制函数

csharp 复制代码
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. 图标获取逻辑

csharp 复制代码
Texture GetComponentIcon(Component component)
{
    // 1. 先获取类型专用图标(如Camera、Light等内置图标)
    Texture typeIcon = AssetPreview.GetMiniTypeThumbnail(component.GetType());
    
    // 2. 如果没有类型图标,获取组件的缩略图(自定义脚本图标)
    if (typeIcon == null) 
    {
        typeIcon = AssetPreview.GetMiniThumbnail(component);
    }
    
    return typeIcon;
}

4. 图标位置计算

csharp 复制代码
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)
    • 没有可用图标的组件

使用效果示例

场景中的显示效果:

用处

  1. 组件可视化

    • 直观展示对象上所有组件
    • 无需展开查看Inspector
  2. 脚本丢失检测

    • 脚本丢失时图标不显示
    • 快速发现损坏的对象
  3. 快速识别

    • 特殊图标表示特定组件
    • 悬停提示显示具体类型名
  4. 顺序指示

    • 图标排列顺序反映组件添加顺序
    • 帮助理解对象结构

使用注意事项

  1. 性能影响

    • 大型场景中可能会影响编辑器性能
    • 建议添加显示对象数量阈值
  2. 兼容性

    • 只兼容 2018.3+ 版本的 Unity
    • 旧版本 Unity 需要使用其他方法
相关推荐
LYOBOYI1233 小时前
vscode界面美化
ide·vscode·编辑器
浔川python社4 小时前
关于浔川代码编辑器 v5.0 网页版上线时间的通知
编辑器
在路上看风景6 小时前
31. Unity 异步加载的底层细节
unity
天人合一peng8 小时前
Unity中做表头时像work中整个调整宽窄
unity
浔川python社8 小时前
浔川代码编辑器 v5.0 上线时间公布
编辑器
山峰哥17 小时前
数据库工程与SQL调优——从索引策略到查询优化的深度实践
数据库·sql·性能优化·编辑器
Doro再努力18 小时前
Vim 快速上手实操手册:从入门到生产环境实战
linux·编辑器·vim
Doro再努力18 小时前
【Linux操作系统10】Makefile深度解析:从依赖推导到有效编译
android·linux·运维·服务器·编辑器·vim
小李也疯狂20 小时前
Unity 中的立方体贴图(Cubemaps)
unity·游戏引擎·贴图·cubemap
牛掰是怎么形成的20 小时前
Unity材质贴图引用陷阱:包体暴涨真相
unity·材质·贴图