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);
    }
}

打个赏吧

相关推荐
国家一级摸鱼选手15 小时前
MCP(Model Context Protocol)学习笔记
unity·ai·mcp
会思考的猴子17 小时前
Unity3D发布后软件界面右下角出现Trial Version
unity
ellis197018 小时前
Unity资源管理框架Addressables[五] 构建
unity
派葛穆19 小时前
Unity-鼠标悬停改变图像位置
unity·计算机外设·交互
avi911120 小时前
图例设计软件:Focusky,VisualComponents,图片字风格化等试用和推荐,最终还是回到Unity 游戏代码
unity·ai·aigc·游戏开发·设计工具·信息图
张老师带你学20 小时前
unity道具,健身房资源
科技·游戏·unity·游戏引擎·模型
废嘉在线抓狂.1 天前
简易拆开即用的高性能计时器(C#)
前端·unity·c#
ellis19701 天前
Unity资源管理框架Addressables[四] 资源分组管理
unity
张老师带你学1 天前
unity道具,哑铃架+天文望远镜,一边运动一边观星
科技·游戏·unity·模型·游戏美术
Swift社区1 天前
如果今天重新做 Claw,会用什么技术
游戏·unity