【第四章自定义编辑器窗口_扩展默认的编辑器窗口_扩展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 需要使用其他方法
相关推荐
DechinPhy4 小时前
VSCode手动版本更新
ide·vscode·编辑器
Sadsvit8 小时前
Linux Vim 编辑器使用指南
linux·编辑器·vim
_别来无恙_9 小时前
vscode 字体的跟换
ide·vscode·编辑器
叶子爱分享16 小时前
VS Code编辑器
编辑器
BuHuaX17 小时前
Unity_UI_NGUI_缓动
ui·unity·c#·游戏引擎·游戏策划
DaLiangChen1 天前
Unity 实时 CPU 使用率监控
unity·游戏引擎
cyr___1 天前
Unity教程(二十四)技能系统 投剑技能(中)技能变种实现
学习·游戏·unity·游戏引擎
LilySesy2 天前
【案例总结】幽灵单据——消失的交货单号
数据库·ai·oracle·编辑器·sap·abap
Chensf20212 天前
安装及使用vscode
ide·vscode·编辑器