The Unity editor extension _______ finds situations where a game object "referenced object" is referenced by other objects in a scene.

Version used: Unity 2018.1.9

Purpose: In the non-running state of the editor, find the situation where the "referenced object" of the game object is persistently referenced by other objects in the scene in a scene. (Persistence is the kind of drag and drop, such as a public variable, you drag and drop assignment), as shown in the figure:

 

The current capacity of reference queries:

You can query whether the public variables of the custom script component refer to the "referenced object" of the game object, as shown in the figure above:

 

You can query whether the public UnityEvent event of the custom script component has a reference to the game object "referenced object":

 

You can query whether the OnClick event of the Button component has a reference to the game object "referenced object":

 

By the way, in the scene, the game object "referenced object" is referenced by the three game objects I showed. Like "public variable - empty" and "public event - empty", there is no reference to the game object "referenced object". As shown in the picture:

 

And those other game objects are just to make up the number, they don't refer to anyone.

 

Operation method: Select your target game object, then right-click the mouse to bring up the menu, select "Find references in the scene (only support single object query)" button and press it.

 

Result: On the console, the names of those game objects that refer to the game object "referenced object" will be printed out one by one.

 

As mentioned above, it is such a function. Not difficult, but tedious. My three reference search methods can basically meet most of the needs. If you want to expand it, you can expand it on the basis of my script. If you don't want to expand, create a script, copy my code, and put the script in the Editor folder.

Here is my code:

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

                }


            }

        }



    }

}

 

Finally, I would like to add that if the script shows that the .Net version is wrong, just set it here to be the same as mine:

 

If you think it's good, please give it a thumbs up! Of course, you can point it out if you think something is wrong.

Guess you like

Origin blog.csdn.net/qq_37760273/article/details/109243395