1. 程式人生 > >Unity Prefab和GameObject的正向和逆向查詢引用

Unity Prefab和GameObject的正向和逆向查詢引用

我發現很多美工兄弟都愛問程式Unity3d為什麼總丟材質? 我不排除U3d有BUG的情況下會丟材質?但是其實很多時候是人為操作而引起的。

1.不儲存就在上傳

這個操作太恐怖了,切記!!在 U3D裡面你無論操作了什麼,當你要上傳svn的時候一定要先儲存場景,Ctrl+S 切記切記!!如果不儲存就上傳很有可能就會丟材質。

2.我的電腦明明沒事,怎麼你哪裡就丟材質?

我發現一個很有意思的現象,每次走到美術電腦前看它的svn工程時,我都會發現各種的“黃歎號”整個工程嚴重的衝突。然後程式和美術的對話就是:“這資源有用沒?沒用刪了, 我重新更新。。。” 哈哈哈 我覺得可能只有程式設計師才會對衝突非常敏感吧,但我覺得這件事不能怪美術,美術是很抽象的東西,不向程式要具體到少一個分號就無法進行了。

3.管理好材質貼圖

如果專案不管理好材質和貼圖,後起你會發現有很多完全一樣的圖片只是名子不一樣,但是還都在使用中。。這個很有可能是好幾個美術同時在做,這樣會造成資源的浪費。

4.特效丟材質

我舉個實際的例子,我們專案場景和特效是兩個人來做。之前總遇到場景特效莫名其妙丟材質的問題。原因就是做特效的人把特效修改了,但是做場景的又不知道,因為可能這個特效在好多場景上都在使用中。

 如下圖所示,在Preiject下面方的Prefab 如果拖入Hierarchy檢視中,它倆是具有關聯關係的,如果你直接在Project檢視中修改了Prefab那麼所有Hierarchy檢視中關聯它的Prefab都會得到修改。小改動這樣是沒問題的,如果發生一些比較大的改動,那麼Hierarchy檢視中Prefab可能就會丟失或者壞掉。但是假如你有很多場景都引用同一個Prefab,這麼多場景會很難找到的。


正向在Hierarch檢視中選擇一個prefab,然後在右側Inspector檢視中點選Select會自動找到Project檢視中的Prefab物件。那麼反向如何從Project檢視中找到Hierarchy檢視中引用的Prefab呢?

如下圖所示,Unity3d做了一個功能,在Project檢視中選擇一個Prefab,然後右鍵選擇Find References In Scene ,那麼此時Unity會自動幫你在當前場景中找到Hierarchy檢視中引用這個Prefab的GameObject。


但是這個方法有點侷限性,就是它只能找到當前場景的,假設你的這個Prefab在很多場景中都引用了,那麼這樣是找不到了,為了美術我決定寫一個小小的工具,嘿嘿。

	[MenuItem("Assets/Check Prefab Use ?")]
	private static void OnSearchForReferences()
	{
	  //確保滑鼠右鍵選擇的是一個Prefab
		if(Selection.gameObjects.Length != 1)
		{
			return;
		}
 
		//遍歷所有遊戲場景
		foreach(EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
		{
			if(scene.enabled)
			{
			  //開啟場景
				EditorApplication.OpenScene(scene.path);
				//獲取場景中的所有遊戲物件
				GameObject []gos = (GameObject[])FindObjectsOfType(typeof(GameObject));
				foreach(GameObject go  in gos)
				{
				  //判斷GameObject是否為一個Prefab的引用
					if(PrefabUtility.GetPrefabType(go)  == PrefabType.PrefabInstance)
					{
						UnityEngine.Object parentObject = EditorUtility.GetPrefabParent(go); 
						string path = AssetDatabase.GetAssetPath(parentObject);
						//判斷GameObject的Prefab是否和右鍵選擇的Prefab是同一路徑。
						if(path == AssetDatabase.GetAssetPath(Selection.activeGameObject))
						{
							//輸出場景名,以及Prefab引用的路徑
							Debug.Log(scene.path  + "  " + GetGameObjectPath(go));
						}
					}
				}
			}
		}
	}
	public static string GetGameObjectPath(GameObject obj)
	{
		string path = "/" + obj.name;
		while (obj.transform.parent != null)
		{
			obj = obj.transform.parent.gameObject;
			path = "/" + obj.name + path;
		}
		return path;
	}
如下圖所示,我就可以找到哪個場景引用了這個Prefab。 這裡我沒有用GameObject和Prefab的名子來判斷,我覺得最好也不要用名字,因為Hierarchy檢視中的名子完全可以隨意修改的,如果被改了的話就肯定找不到了,而且場景那麼多完全有重名的情況。


是不是很簡單呢?嘿嘿。

或者還有個辦法,就是執行時動態的載入Prefab,但是有些場景特效其實萬全沒有任何意義,僅僅是展示而已,程式也無需對它進行操作。

有了這個小工具,那麼以後美術改完Prefab的時候,執行一下連帶的看看某些場景上是否正常的顯示了?嘿嘿嘿嘿。