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。在這樣的狀況下,就須要再對那個文件作遍歷。直到沒有間接引用,才能獲取真正全部的引用。