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

打个赏吧

相关推荐
超龄魔法少女7 小时前
[Unity] ShaderGraph动态修改Keyword Enum,实现不同效果一键切换
unity·技术美术·shadergraph
蔗理苦9 小时前
2024-12-24 NO1. XR Interaction ToolKit 环境配置
unity·quest3·xr toolkit
花生糖@9 小时前
Android XR 应用程序开发 | 从 Unity 6 开发准备到应用程序构建的步骤
android·unity·xr·android xr
向宇it9 小时前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
向宇it13 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
向宇it19 小时前
【从零开始入门unity游戏开发之——C#篇26】C#面向对象动态多态——接口(Interface)、接口里氏替换原则、密封方法(`sealed` )
java·开发语言·unity·c#·游戏引擎·里氏替换原则
神码编程1 天前
【Unity功能集】TextureShop纹理工坊(五)选区
unity·游戏引擎·shader·ps选区
m0_748251721 天前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
benben0441 天前
Unity3D仿星露谷物语开发7之事件创建动画
unity·游戏引擎
林枫依依1 天前
Unity2021.3.16f1可以正常打开,但是Unity2017.3.0f3却常常打开闪退或者Unity2017编辑器运行起来就闪退掉
unity