Unity插件开发:SerializedObject/SerializedProperty——查找引用的资源

        Unity有一个Find References in Scene功能非常好用。在Project面板中右键一个文件,选择Find References in Scene就可以在场景中找到所有存在对这个文件有引用的物体。但是很多时候,我们更加需要知道的是,这个场景里面到底引用了哪些文件,比如做优化的时候。

        这里有一个插件叫做ResourceChecker,它可以列举出所有引用到的texture/mesh/mat等。但是他也有一个小小的问题,对于自定义脚本的引用没有效果。

        要实现这个需求,这里主要借助SerializedObject/SerializedProperty。参考官方文档:

        SerializedProperty在CustomEditor会经常用到,可以用于反射一个Unity对象的字段(甚至可以可以反射private字段,非常暴力)。

        在《Unity文件、文件引用、meta详解》一文中,曾经提到过unity资源序列化的数据要么是存在meta中,要么就是本身那个资源。比如用Notepad++打开prefab文件后,可能会是这样的yaml序列化数据。而这些数据都可以通过SerializedProperty获取得到。

        在上图的例子中可以看到,Property名字为m_PrefabInternal,它的Value中,fileID不为0。由此可以看到这个物体引用了一个对象。

        下面,我们用代码来寻找一个Prefab中引用到指定类型的所有文件,比如Sprite。

    public static void FindRef<T>(SerializedObject obj) where T : Object
    {
        var prop = obj.GetIterator();
        while (prop.Next(true))
        {
            if (prop.propertyType == SerializedPropertyType.ObjectReference)
            {
                var value = prop.objectReferenceValue;
                if (value is T)
                {
                    var path = AssetDatabase.GetAssetPath(value);
                    Debug.Log(prop.propertyPath + ":" + path);
                }
            }
        }
    }

       这里有几个API

  • SerializedObject.GetIterator:获取这个SerializedObject上的初始SerializedProperty。用这个SerializedProperty可以逐个列举出下一个SerializedProperty
  • SerializedProperty.Next:获取下一个SerializedProperty,如果参数为true,就会进入子字段Object的Property.比如一个mono脚本上有A字段,A字段是一个class,它有自己若干个可序列的字段,那么就会逐个列举这些字段的SerializedProperty。
  • SerializedProperty.propertyType:字段的类型,比如是引用,数字,字符等等,见SerializedPropertyType。每一种Type对应的值的类型也是不一样
  • SerializedProperty.objectReferenceValue,引用类型的字段的值。由于这里我们主要查找的是对文件的引用,所以引用的对象肯定在objectReferenceValue中
  • SerializedProperty.propertyPath,字段在这个SerializedObject中的路径。正如上面所言,这个字段可能是属于子字段的,所以有路径之说

       所以,这段代码就是,逐个遍历一个SerializedObject中的所有字段,如果是对象引用的,并且对象的值是我们想要的类型,那么找出在工程中的路径,打印出来。

       我们扩充一下,增加以下函数

    public static void FindRefWithGameObject<T>(GameObject obj) where T : Object
    {
        var coms = obj.GetComponentsInChildren<Component>();
        foreach (var com in coms)
        {
            var so = new SerializedObject(com);
            FindRef<T>(so);
        }
    }

        很简单,找到一个GameObject物体下的所有组件,转为SerializedObject,然后用之前的函数,把每一个组件下,引用到指定T类型的资源的字段全部打印出来。

        最后,我们真正来找出所有引用到的Sprite

    [MenuItem("Assets/Test/FindSprite")]
    public static void FindSprite()
    {
        var select = Selection.activeGameObject;
        if (select == null)
            return;
        FindRefWithGameObject<Sprite>(select);
    }

       OK,在一个Prefab上右键,选择Test->FindSprite,可以看到打印出所有的引用信息了

      在这个demo中可以看到包含了Image控件中的Sprite引用,Button中切换的Sprite引用,自定义脚本Test中对Sprite的引用

       至此完成了大部分的引用信息获取。这里还有一个问题,没有间接引用的信息,比如,Test脚本中引用一个Animation或者其他文件,而这些文件又引用到Sprite。在这样的情况下,就需要再对那个文件做遍历。直到没有间接引用,才能获取真正所有的引用。

原文地址:https://www.cnblogs.com/CodeGize/p/9180610.html

时间: 2024-09-29 16:32:44

Unity插件开发:SerializedObject/SerializedProperty——查找引用的资源的相关文章

Unity插件开发:PrefabUtility--Prefab实例引用断开和替换

在Unity使用Prefab过程中,我们有时候需要进行Prefab实例断开引用和替换引用的需求.实现这些需求,使用到的核心的类是PrefabUtility.PrefabUtility是一个静态类,主要用于进行Prefab的相关处理. 这里主要使用以下几种方法 PrefabUtility.CreateEmptyPrefab PrefabUtility.ReplacePrefab PrefabUtility.DisconnectPrefabInstance PrefabUtility.GetPref

让Tomcat支持引用软连接资源

默认情况下想通过在Tomcat下建立软连接来使tomcat上的应用引用该资源是不行的.会出现类似错误: java.lang.IllegalStateException: ContainerBase.addChild: start: LifecycleException: start: : java.io.IOException: Failed to access resource XXX 这时候需要打开支持引用软连接资源的开关:allowLinking="true", 比如在conte

Windows Store App 全球化:引用类库资源

前面几个小节介绍了如何引用自身项目的资源,而有时在应用程序开发过程中可能需要访问其他项目中的资源.例如,当几个人或十几个人一起设计一个解决方案时,每个人的工作都是不同的,编写的项目也是不同的,但是每个人都可能需要访问其他项目的某些资源,这就引入了类库资源的概念.对于每一个项目都能够引用的资源,我们称它为类库资源.下面通过一个示例具体讲解如何引用类库中的资源. 新建一个Windows应用商店的空白应用程序项目,并命名为GetClassLibraryResources.在解决方案资源管理器中,右键单

Windows Store App 全球化:引用分离资源文件中的资源

大部分应用程序仅需要单个默认资源文件,例如Strings/zh-CN/Resources.resw,但是在某些应用程序中,最好将资源分离到多个资源文件中,以便更好地组织资源内容,这样就需要考虑如何引用这些分离资源文件中的资源.下面通过一个示例讲解如何在后台代码中引用分离资源文件中的字符串资源. 新建一个Windows应用商店的空白应用程序项目,并命名为SeparatedResourcesFiles.在项目中添加如18.2.3小节示例中相同的语言文件夹.资源文件以及资源信息.完成上述操作后,在"z

notepad++ 查找引用(Find Reference)(适用于c c++及各类脚本比如lua)

在程序开发过程中,程序员经常用到的一个功能就是查找引用(Find Reference),Visual Studio里面的对应功能是"查找所有引用"(Find All References). 本人在使用notepad++写代码的时候一直因为找不到类似的功能和苦恼.只好每次使用"在文件中查找"(Find in files)来找到所有引用. 但是这样每次查找都需要遍历目标目录的整个文件系统,文件多的话会耗费很长时间. notepad++有插件可以实现同样的功能,但是相比

notepad++ 查找引用(Find Reference)(适用于c c++及各类脚本比如lua、python等)

在程序开发过程中,程序员经常用到的一个功能就是查找引用(Find Reference),Visual Studio里面的对应功能是“查找所有引用”(Find All References). 我在使用notepad++写代码的时候一开始一直因为找不到类似的功能而苦恼.只好每次使用“在文件中查找”(Find in files)来找到所有引用. 但是这样每次查找都需要遍历目标目录的整个文件系统,文件多的话会耗费很长时间. notepad++有插件可以实现查找引用的功能.相比于搜索整个文件系统,这种插

JAVA实现EXCEL公式专题(六)——查找引用函数

查找引用函数主要有match.lookup.vlookup.hlookup这4种,这几个常用的方法也就不解释啦,直接上干货: /** * 项目名称: * 文件说明: * 主要特点: EXCEL公式类型:查找公式 * 版本号:1.0 * 制作人:刘晨曦 * 创建时间:2013-12-3 **/ package EXCEL; import java.util.Calendar; import java.util.Date; /** * @author lcx * */ public class Se

wpf资源嵌套,一个资源引用另外一个资源,被引用的资源应该声明在前面

在wpf的XAML的Window.Resources中,一个资源引用另外一个资源,出现如下错误: “错误 1 “{DependencyProperty.UnsetValue}”不是 Setter 上“System.Windows.FrameworkElement.FocusVisualStyle”属性的有效值”. 如下图: 虽然错误列表里出现如图的错误,但是程序缺依然可以运行,只是在设计器里看不了UI视图(界面). 出现这个错误的原因是: 被引用的资源的声明在引用它的资源的后面了(或者是没有声明

【Unity】2.3 项目浏览器和资源的组织

分类:Unity.C#.VS2015 创建日期:2016-03-29 一.Project-工程浏览器 前面我们说过,Unity中的Project View(称为工程浏览器)相当于VS2015中的解决方案资源管理器(Solution),Unity的每个工程中可包含多个关卡(*.unity),每个关卡都是一个可独立运行的项目,根据发布的目标平台不同,编译后生成的可执行程序的扩展名也不同,例如对于Windows平台生成的可执行程序是(.exe文件),对于在Windows平台下运行的浏览器(Web)生成