Unity有一个Find References in Scene功能很是好用。在Project面板中右键一个文件,选择Find References in Scene就能够在场景中找到全部存在对这个文件有引用的物体。可是不少时候,咱们更加须要知道的是,这个场景里面到底引用了哪些文件,好比作优化的时候。html
这里有一个插件叫作ResourceChecker,它能够列举出全部引用到的texture/mesh/mat等。可是他也有一个小小的问题,对于自定义脚本的引用没有效果。git
要实现这个需求,这里主要借助SerializedObject/SerializedProperty。参考官方文档:github
SerializedProperty在CustomEditor会常常用到,能够用于反射一个Unity对象的字段(甚至能够能够反射private字段,很是暴力)。函数
在《Unity文件、文件引用、meta详解》一文中,曾经提到过unity资源序列化的数据要么是存在meta中,要么就是自己那个资源。好比用Notepad++打开prefab文件后,可能会是这样的yaml序列化数据。而这些数据均可以经过SerializedProperty获取获得。优化
在上图的例子中能够看到,Property名字为m_PrefabInternal,它的Value中,fileID不为0。由此能够看到这个物体引用了一个对象。spa
下面,咱们用代码来寻找一个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); } } } }
这里有几个API3d
因此,这段代码就是,逐个遍历一个SerializedObject中的全部字段,若是是对象引用的,而且对象的值是咱们想要的类型,那么找出在工程中的路径,打印出来。code
咱们扩充一下,增长如下函数orm
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。在这样的状况下,就须要再对那个文件作遍历。直到没有间接引用,才能获取真正全部的引用。