Unity Editor实用功能:Hierarchy面板的对象上绘制按按钮并响应

目录

需求描述

现在有这样一个需求:

  • 在Hierarchy面板的对象上绘制按钮
  • 点击按钮,弹出菜单
  • 再点击菜单项目响应自定义操作
  • 在这里的响应主要是复制对象层级路路径
    看具体效果请看动图:

注:

  • 核心是对EditorApplication.hierarchyWindowItemOnGUI委托的实现
  • 其它需求,可参考实现
  • 如是要要Project面板实现类似的功能:可以参考实现EditorApplication.hierarchyWindowItemOnGUI委托

上代码

csharp 复制代码
/**********************************************
 * @author: anyuanlzh
 * @date: 2023-05-18
 * @des:  "Hierarchy面板"工具
 ***********************************************/

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
public class HierarchyTabTool
{
    // 静态构造函数
    static HierarchyTabTool()
    {
      EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI;
    }
    private static void HierarchyWindowItemOnGUI(int instanceId, Rect selectionRect)
    {
      var obj = EditorUtility.InstanceIDToObject(instanceId) as GameObject;
      if (obj == null)return;
      GameObject selectedObjs = Selection.activeGameObject;
      if(obj!=selectedObjs)return;

      selectionRect.x += selectionRect.width - 60;
      selectionRect.y += 0;
      selectionRect.width = 60f;
      GUIStyle fontStyle = new GUIStyle(GUI.skin.button);
      fontStyle.alignment=TextAnchor.MiddleCenter;
      fontStyle.fontSize=10;
      fontStyle.normal.textColor=Color.yellow;
      //点击事件
      if (GUI.Button(selectionRect, "复制层级", fontStyle))
      {
           // Debug.Log($"click: {Selection.activeObject.name}");
           // 弹出菜单
           Vector2 mousePosition = Event.current.mousePosition;
           Rect position = new Rect(mousePosition.x, mousePosition.y+7, 0, 0);
           EditorUtility.DisplayPopupMenu(position, "GameObject/1_复制层级路径", null);
      }
    }

	// 防止一次点击响应多次
    private static float _last_call_time = 0;
    private static float minInterval_time = 0.5f;

    [MenuItem("GameObject/1_复制层级路径/A点~B点", false, 40)]
    private static void GetHierarchyPath2()
    {
      if (Time.time - _last_call_time<minInterval_time)
      {
           return;
      }
      _last_call_time = Time.time;

      GameObject[] selectedObjs = Selection.gameObjects;
      //Debug.Log(selectedObjs.Length);
      if (selectedObjs.Length == 1)
      {
           Copy_HierarchyPath_root2target();
           return;
      }
      else if (selectedObjs.Length < 2)
      {
           Debug.Log("请选择一个或二个有包含关系对象");
           return;
      }

      Transform first = selectedObjs[0].transform;
      Transform last = selectedObjs[selectedObjs.Length-1].transform;
      // Debug.Log($"first.name:{first.name} last.name:{last.name}");
      Transform a = null;
      Transform b = null;
      if (EditorUtils.IsAncestor(first, last))
      {
           a = first;
           b = last;
      }
      else if (EditorUtils.IsAncestor(last, first))
      {
           a = last;
           b = first;
      }
      else
      {
           Debug.LogError("请选择有包含关系的二个对象");
           return;
      }

      List<string> names = new List<string>();
      while (b!=null)
      {
           if (a == b)
           {
                names.Insert(0,b.name);
                break;
           }
           names.Insert(0, b.name);
           b = b.parent;
      }
      string path = "";
      for (int i = 0; i < names.Count-1; i++)
      {
           path += names[i] + "/";
      }
      path += names[^1];
      GUIUtility.systemCopyBuffer = path;
      Debug.Log("对象层次路径 A点到B点: " + path);
    }

    [MenuItem("GameObject/1_复制层级路径/根0~目标", false, 40)]
    private static void Copy_HierarchyPath_root0target()
    {
      Copy_HierarchyPath_rootN2target(0);
    }
    [MenuItem("GameObject/1_复制层级路径/根1~目标", false, 40)]
    private static void Copy_HierarchyPath_root1target()
    {
      Copy_HierarchyPath_rootN2target(1);
    }
    [MenuItem("GameObject/1_复制层级路径/根2~目标", false, 40)]
    private static void Copy_HierarchyPath_root2target()
    {
      Copy_HierarchyPath_rootN2target(2);
    }
    [MenuItem("GameObject/1_复制层级路径/根3~目标", false, 40)]
    private static void Copy_HierarchyPath_root3target()
    {
      Copy_HierarchyPath_rootN2target(3);
    }
    // 从根0的第N级到目标
    // rootN从零开
    static void Copy_HierarchyPath_rootN2target(int rootN)
    {
      if (Time.time - _last_call_time<minInterval_time)
      {
           return;
      }
      _last_call_time = Time.time;

      if (Selection.count != 1)
      {
           Debug.LogError($"Copy_HierarchyPath_rootN2target: 请选择一个对象");
           return;
      }

      Transform target = Selection.activeGameObject.transform;
      List<string> names = new List<string>();
      Transform parent = target.transform.parent;
      while (target != null)
      {
           names.Insert(0, target.name);
           target = target.parent;
      }
      if (names.Count - 1 < rootN)
      {
           Debug.LogError($"Copy_HierarchyPath_rootN2target: N:{rootN}大于目标对象的深度");
           return;
      }

      string path = "";
      for (int i = rootN; i < names.Count-1; i++)
      {
           path += names[i] + "/";
      }
      path += names[^1];
      GUIUtility.systemCopyBuffer = path;
      Debug.Log($"对象层次路径 root_{rootN}到target:" + path);
    }
}

打个赏吧

相关推荐
小春熙子9 小时前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
Sitarrrr12 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧12 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
逐·風20 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i21 小时前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
Leoysq1 天前
【UGUI】实现点击注册按钮跳转游戏场景
游戏·unity·游戏引擎·ugui
_oP_i1 天前
unity中 骨骼、纹理和材质关系
unity·游戏引擎·材质
Padid2 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
Tp_jh2 天前
推荐一款非常好用的C/C++在线编译器
linux·c语言·c++·ide·单片机·unity·云原生
dangoxiba2 天前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十八集补充:制作空洞骑士独有的EventSystem和InputModule
游戏·unity·c#·游戏引擎·playmaker