欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Unity编辑器拓展_______查找一个场景中,游戏物体 “被引用的物体” 被其他物体引用的情况。

程序员文章站 2022-03-16 08:11:31
所用版本:Unity 2018.1.9目的:在编辑器内非运行状态下,查找一个场景中,游戏物体 “被引用的物体” 被场景内其他物体持久化引用的情况。(持久化就是拖拽的那种,比如一个公开变量,你拖拽赋值),如图:目前引用查询的本领大小:可以查询自定义脚本组件的公开变量是否有引用游戏物体 “被引用的物体”,见上图:可以查询自定义脚本组件的公开UnityEvent事件是否有引用游戏物体 “被引用的物体”:可以查询Button组件的OnClick事件是否有引用游戏物体 “......

所用版本:Unity 2018.1.9

目的:在编辑器内非运行状态下,查找一个场景中,游戏物体 “被引用的物体” 被场景内其他物体持久化引用的情况。(持久化就是拖拽的那种,比如一个公开变量,你拖拽赋值),如图:

Unity编辑器拓展_______查找一个场景中,游戏物体  “被引用的物体”  被其他物体引用的情况。

 

目前引用查询的本领大小:

可以查询自定义脚本组件的公开变量是否有引用游戏物体 “被引用的物体”,见上图:

 

可以查询自定义脚本组件的公开UnityEvent事件是否有引用游戏物体 “被引用的物体”:

Unity编辑器拓展_______查找一个场景中,游戏物体  “被引用的物体”  被其他物体引用的情况。

 

可以查询Button组件的OnClick事件是否有引用游戏物体 “被引用的物体”:

Unity编辑器拓展_______查找一个场景中,游戏物体  “被引用的物体”  被其他物体引用的情况。

 

提一嘴,场景中,就我展示的这三个游戏物体引用了游戏物体  "被引用的物体" 。像“公开变量——空”和“公开事件——空”,是没有引用游戏物体 "被引用的物体" 的。如图:

Unity编辑器拓展_______查找一个场景中,游戏物体  “被引用的物体”  被其他物体引用的情况。

Unity编辑器拓展_______查找一个场景中,游戏物体  “被引用的物体”  被其他物体引用的情况。

 

而其他的那些个游戏物体,就是来凑个数的,它们没有引用任何人。

 

操作方法:选中你的目标游戏物体,然后鼠标右键单击,调出菜单,选择 “查找场景内引用(只支持单个物体查询)” 按钮按下去就行了。

Unity编辑器拓展_______查找一个场景中,游戏物体  “被引用的物体”  被其他物体引用的情况。

 

结果:会在控制台,把引用了游戏物体 “被引用的物体” 的 那些游戏物体名称一一打印出来。

Unity编辑器拓展_______查找一个场景中,游戏物体  “被引用的物体”  被其他物体引用的情况。

 

如上所述,就是这么一个功能。不算难,但挺繁琐。我的三种引用查找方式,基本上能满足大部分需求,如果想要再拓展,在我的脚本基础上拓展就行了。不想拓展的话,创建个脚本,把我的代码复制下,然后把脚本放到Editor文件夹就行了。

下面就是我的代码:

using UnityEngine;
using UnityEditor;
using System.Reflection;
using UnityEngine.UI;
using UnityEngine.Events;
using System.Collections;
using System;
using System.Collections.Generic;
using System.Linq;


/// <summary>
/// 查找被选中的单个GameObject在场景中所有被其他脚本、事件引用的地方
/// </summary>
public class FindGameObjectInScene
{

    /// <summary>
    /// 获取当前被选中的游戏物体的InstanceID,这个值是系统自动赋予的,且是唯一的。
    /// </summary>
    static int SelectedObjID=0;

    /// <summary>
    /// 记录总共有多少个脚本、事件等引用了当前被“鼠标选中的游戏物体”
    /// </summary>
    static int referenceCount = 0;

    /// <summary>
    /// 假设你要搜查的是一个Button组件,Button组件引用其他物体的方式,就是给点击事件上引用游戏物体或游戏物体的组件。
    /// 这个变量是记录按钮组件的点击事件上绑定方法数量的。
    /// </summary>
    static int buttonEventMethodCount = 0;


    //假如被搜查的游戏物体身上有个自定义的组件,组件中有UnityEvent事件类型的公开变量,就需要去再搜查一遍
    //这个事件上绑定的方法。 思路和搜索按钮事件一样。
    /// <summary>
    /// 这个变量是记录自定义组件的UnityEvent事件上绑定方法数量的。
    /// </summary>
    static int unityEventMethodCount = 0;






    [MenuItem("GameObject/查找场景内引用(只支持单个物体查询)", false, priority = -1)]
    static void StartFindReference()
    {

        //开始标记,输出的文字颜色为绿色
        Debug.Log($"-><color=#006400>开始查找游戏物体</color> <color=#FF0000>“{Selection.transforms[0].gameObject.name}”</color> <color=#006400>在场景内的所有引用!!!</color>");

        //获取当前被选中的游戏物体的InstanceID,这个值是系统自动赋予的,且是唯一的。
        SelectedObjID = Selection.transforms[0].gameObject.GetInstanceID();

        //获取当前场景中所有的游戏物体
        List<GameObject>currentSceneAllGameObject = GetAllSceneObjectsWithInactive();

        //从列表中移除“鼠标选中的游戏物体”,没有自己搜查自己的必要
        currentSceneAllGameObject.Remove(Selection.transforms[0].gameObject);

        //输出场景中游戏物体总数
        Debug.Log($"-><color=#006400>场景*有</color> <color=#FF0000> {currentSceneAllGameObject.Count} </color> <color=#006400>个游戏物体,不包括“鼠标选中物体”本身!!!</color>");

        //循环执行,对每一个场景中的游戏物体进行筛选查找,判断它是否有引用当前被鼠标指针选中的游戏物体
        for (int i = 0; i < currentSceneAllGameObject.Count; i++)
        {
            GameObject go = currentSceneAllGameObject[i];
            Find(go);
        }

        //输出场景中,有引用“鼠标选中的物体”的游戏物体数量
        Debug.Log($"-><color=#006400>“鼠标选中的物体”被</color> <color=#FF0000> {referenceCount} </color> <color=#006400>个游戏物体所引用</color>");

        //重置化全局变量
        SelectedObjID = 0;
        referenceCount = 0;
        buttonEventMethodCount = 0;
        unityEventMethodCount = 0;


        //结束标记,输出的文字颜色为绿色
        Debug.Log($"-><color=#006400>{"查找结束!!!"}</color>");

    }



    [MenuItem("GameObject/查找场景内引用(只支持单个物体查询)", true)]
    static bool StartFindReferenceValidate()
    {
        //假如有选中场景中的物体,且只选中了一个
        return Selection.transforms.Length == 1;
    }




    //用于获取所有Hierarchy中的物体,包括激活的和被禁用的物体
    private static List<GameObject> GetAllSceneObjectsWithInactive()
    {
        var allTransforms = Resources.FindObjectsOfTypeAll(typeof(Transform));
        var previousSelection = Selection.objects;
        Selection.objects = allTransforms.Cast<Transform>()
            //C#中Linq的一些操作
            .Where(x => x != null)
            .Select(x => x.gameObject)
            //如果你只想获取 所有 在Hierarchy中 被禁用 的物体,反注释下面一句代码
            //.Where(x => x != null && !x.activeInHierarchy)
            .Cast<UnityEngine.Object>().ToArray();

        var selectedTransforms = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
        Selection.objects = previousSelection;
        return selectedTransforms.Select(tr => tr.gameObject).ToList();

    }


    /// <summary>
    /// 获得GameObject在Hierarchy中的完整路径
    /// </summary>
     static string GetTransPath(Transform trans)
    {
        if (!trans.parent)
        {
            return trans.name;

        }
        return GetTransPath(trans.parent) + "/" + trans.name;
    }




    /// <summary>
    /// 查找当前循环到的游戏物体,是否有引用被鼠标选中的那个游戏物体
    /// </summary>
    /// <param name="go"></param>
    static void Find(GameObject go)
    { 

        //获取当前循环到的游戏物体身上的所有组件
        Component[] components = go.GetComponents<Component>();

        //循环遍历每一个组件,看他们之中的某个变量是否有引用“鼠标选中的游戏物体”
        for (int i = 0; i<components.Length; i++)
        {

            //假设当前组件为UGUI按钮类型
            if(components[i].GetType()== typeof(Button))
            {

                //拿到当前Button组件的引用
                Button currentButton = components[i] as Button;

                //设置当前按钮组件点击事件上绑定方法的数量  GetPersistentEventCount为获得持久化方法数量函数
                buttonEventMethodCount = currentButton.onClick.GetPersistentEventCount();

                //循环遍历按钮点击事件列表,从事件列表中找一下,
                //看列表中是否包含我们“鼠标选中的游戏物体”所拥有的方法,如果包含的话,
                //就代表这个按钮组件,或者说拥有这个按钮组件的游戏物体,有引用“鼠标选中的游戏物体”
                for (int m = 0; m < buttonEventMethodCount; m++)
                {
                    //判断被按钮事件引用的究竟是游戏物体 ,还是游戏物体上挂载的组件
                    UnityEngine.Object PersistentTarget = currentButton.onClick.GetPersistentTarget(m);

                    if(PersistentTarget==null)
                    {
                        continue;
                    }
                    //被引用的是游戏物体(GameObject)类型 
                    if (PersistentTarget is GameObject)
                    {
                        //直接将游戏物体的ID和“鼠标选中的游戏物体”的ID进行比对,判断是否一致
                        if (PersistentTarget.GetInstanceID() == SelectedObjID)
                        {
                            referenceCount += 1;
                            Debug.Log($"-><color=#006400>游戏物体</color> <color=#FF0000> {GetTransPath(go.transform)} </color> <color=#006400>引用了被查找的物体</color>");
                            return; 
                        }
                    }
                    //被引用的是组件(Component)类型
                    else if (PersistentTarget is Component)
                    {
                        //将被引用的Object转化为组件
                        Component PersistentTargetComponent = PersistentTarget as Component;

                        //首先获取组件对应的游戏物体,再将游戏物体ID和“鼠标选中的游戏物体”的ID进行比对,判断是否一致
                        if (PersistentTargetComponent.gameObject.GetInstanceID() == SelectedObjID)
                        {
                            referenceCount += 1;
                            Debug.Log($"-><color=#006400>游戏物体</color> <color=#FF0000> {GetTransPath(go.transform)} </color> <color=#006400>引用了被查找的物体</color>");
                            return;
                        }
                    }

                }
            }

            //假设当前被搜查的游戏物体的当前组件为未知类型,或者说,是你无法指定的类型
            else
            {

                //无法预测被搜查的组件是什么类型,就只能用基类Component来存储引用了
                Component component = components[i];

                //BindingFlags   修饰符标志,搜索组件内对应的条件的变量  可自行百度搜索看其含义
                //获取当前组件中,所有公开的成员变量
                FieldInfo[] fields = component.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);

                //循环遍历当前组件中的所有公开的成员变量
                for (int j = 0; j < fields.Length; j++)
                {
                    //尝试获取当前的公开成员变量的值
                    var value = fields[j].GetValue(component);

                    //进行安全性校验,判断是否为空
                    if (value ==null|| value.Equals(null))
                    {
                        continue;
                    }

                    //游戏物体(GameObject)类型
                    if (value is GameObject)
                    {
                        //直接将游戏物体的ID和“鼠标选中的游戏物体”的ID进行比对,判断是否一致
                        if ((value as GameObject).GetInstanceID() == SelectedObjID)
                        {
                            referenceCount += 1;
                            Debug.Log($"-><color=#006400>游戏物体</color> <color=#FF0000> {GetTransPath(go.transform)} </color> <color=#006400>引用了被查找的物体</color>");
                            return;
                        }
                    }

                    //组件(Component)类型
                    else if (value is Component)
                    {
                        //首先获取组件对应的游戏物体,再将游戏物体ID和“鼠标选中的游戏物体”的ID进行比对,判断是否一致
                        if ((value as Component).gameObject.GetInstanceID() == SelectedObjID)
                        {
                            referenceCount += 1;
                            Debug.Log($"-><color=#006400>游戏物体</color> <color=#FF0000> {GetTransPath(go.transform)} </color> <color=#006400>引用了被查找的物体</color>");
                            return;
                        }
                    }

                    //事件(UnityEvent)类型
                    else if (value is UnityEvent)
                    {
                        //将成员变量转化为UnityEvent类型
                        UnityEvent currentEvent = value as UnityEvent;
                       // 设置当前组件UnityEvent事件上绑定方法的数量   GetPersistentEventCount为获得持久化方法数量函数
                        unityEventMethodCount = currentEvent.GetPersistentEventCount();
                        for (int m = 0; m < unityEventMethodCount; m++)
                        {

                            //判断被UnityEvent事件引用的究竟是游戏物体 ,还是游戏物体上挂载的组件
                            UnityEngine.Object PersistentTarget = currentEvent.GetPersistentTarget(m);

                            if (PersistentTarget == null)
                            {
                                continue;
                            }

                            //被引用的是游戏物体(GameObject)类型
                            if (PersistentTarget is GameObject)
                            {
                                //直接将游戏物体的ID和“鼠标选中的游戏物体”的ID进行比对,判断是否一致
                                if (PersistentTarget.GetInstanceID() == SelectedObjID)
                                {
                                    referenceCount += 1;
                                    Debug.Log($"-><color=#006400>游戏物体</color> <color=#FF0000> {GetTransPath(go.transform)} </color> <color=#006400>引用了被查找的物体</color>");
                                    return;
                                }
                            }
                            //被引用的是组件(Component)类型
                            else if (PersistentTarget is Component)
                            {
                                //将被引用的Object转化为组件
                                Component PersistentTargetComponent = PersistentTarget as Component;

                                //首先获取组件对应的游戏物体,再将游戏物体ID和“鼠标选中的游戏物体”的ID进行比对,判断是否一致
                                if (PersistentTargetComponent.gameObject.GetInstanceID() == SelectedObjID)
                                {
                                    referenceCount += 1;
                                    Debug.Log($"-><color=#006400>游戏物体</color> <color=#FF0000> {GetTransPath(go.transform)} </color> <color=#006400>引用了被查找的物体</color>");
                                    return;
                                }
                            }
                        }
                    }

                }


            }

        }



    }

}

 

最后,补充一点,如果脚本哪里显示.Net版本不对的话,在这里设置成和我一致就行:

Unity编辑器拓展_______查找一个场景中,游戏物体  “被引用的物体”  被其他物体引用的情况。

 

如果你觉得不错,麻烦点个赞呗!当然,有认为不对的地方,也可以指出来。

本文地址:https://blog.****.net/qq_37760273/article/details/109243395