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

打个赏吧

相关推荐
ttod_qzstudio13 小时前
Unity中使用EzySlice实现模型切割与UV控制完全指南
unity
南無忘码至尊13 小时前
Unity 实现与 Ollama API 交互的实时流式响应处理
unity·游戏引擎·交互
平行云17 小时前
如何实现UE程序大并发多集群的像素流部署
unity·ue5·图形渲染
向宇it2 天前
【unity小技巧】在 Unity 中将 2D 精灵添加到 3D 游戏中,并实现阴影投射效果,实现类《八分旅人》《饥荒》等等的2.5D游戏效果
游戏·3d·unity·编辑器·游戏引擎·材质
向宇it2 天前
Unity Universal Render Pipeline/Lit光照材质介绍
游戏·unity·c#·游戏引擎·材质
__water2 天前
RHA《Unity兼容AndroidStudio打Apk包》
android·unity·jdk·游戏引擎·sdk·打包·androidstudio
两水先木示3 天前
【Unity3D】微信小游戏适配安全区域或胶囊控件(圆圈按钮)水平高度一致方案
unity·微信小游戏·安全区域·ui适配·胶囊控件·safearea
枯萎穿心攻击3 天前
ECS由浅入深第三节:进阶?System 的行为与复杂交互模式
开发语言·unity·c#·游戏引擎
不绝1913 天前
怪物机制分析(有限状态机、编辑器可视化、巡逻机制)
网络·游戏·unity·游戏引擎
unicrom_深圳市由你创科技3 天前
Unity开发如何解决iOS闪退问题
unity·ios·蓝桥杯