在Unity使用Prefab過程中,我們有時候需要進行Prefab實例斷開引用和替換引用的需求。實現這些需求,使用到的核心的類是PrefabUtility。PrefabUtility是一個靜態類,主要用於進行Prefab的相關處理。 這里主要使用以下幾種方法
- PrefabUtility.CreateEmptyPrefab
- PrefabUtility.ReplacePrefab
- PrefabUtility.DisconnectPrefabInstance
- PrefabUtility.GetPrefabParent
- PrefabUtility.ConnectGameObjectToPrefab
斷開引用
斷開Prefab引用的代碼如下
[MenuItem("Tools/Prefab/去除引用")]
public static void BreakPrefabRef()
{
var select = Selection.activeGameObject;
if (select.activeInHierarchy)
{
PrefabUtility.DisconnectPrefabInstance(select);
Selection.activeGameObject = null;
var prefab = PrefabUtility.CreateEmptyPrefab("Assets/empty.prefab");
PrefabUtility.ReplacePrefab(select, prefab, ReplacePrefabOptions.ConnectToPrefab);
PrefabUtility.DisconnectPrefabInstance(select);
AssetDatabase.DeleteAsset("Assets/empty.prefab");
}
}
雖然PrefabUtility.DisconnectPrefabInstance有斷開Prefab的含義,但是如果僅僅使用這個函數會出現下面這個情況,名字的顏色從藍變白,看起來已經不是一個prefab,但是從Inspector面板中還是能夠看到Prefab標記以及Prefab實例才會出現的那三個Select、Revert、Apply按鈕。
如果嘗試在這個時候刪除掉Project里面的源prefab,發現這個prefab標記就消失了。
因此,這里采用以下方法實現整個斷開引用
- 使用Selection.activeGameObject獲取當前選中的物體
- 使用PrefabUtility.CreateEmptyPrefab先創建一個空的prefab
- 使用PrefabUtility.ReplacePrefab將場景中選中的Prefab實例制作成一個Prefab並覆蓋到之前的空prefab上
- 使用PrefabUtility.DisconnectPrefabInstance斷開引用
- 使用AssetDatabase.DeleteAsset刪除Project中新建的prefab
至此就完成了斷開引用的功能。這里在函數加上[menuitem]標簽,將這個功能放在unity菜單“Tools->Prefab->去除引用”上。
替換引用
替換引用的代碼如下
[MenuItem("Tools/Prefab/替換引用")]
public static void RelocalPrefabRef()
{
var select = Selection.activeGameObject;
if (select.activeInHierarchy)
{
var ab = PrefabUtility.GetPrefabParent(select);
if (ab == null)
return;
var oripath = AssetDatabase.GetAssetPath(ab);
var filters = new[] { "prefab file", "prefab" };
var tar = EditorUtility.OpenFilePanelWithFilters("select target", Application.dataPath, filters);
if (string.IsNullOrEmpty(tar))
return;
tar = FileUtil.GetProjectRelativePath(tar);
var tarprefab = AssetDatabase.LoadAssetAtPath<GameObject>(tar);
if (tarprefab == null)
return;
var gname = select.name;
var enable = select.activeInHierarchy;
var pos = select.transform.localPosition;
var rot = select.transform.localRotation;
var scale = select.transform.localScale;
var go = PrefabUtility.ConnectGameObjectToPrefab(select, tarprefab);
go.transform.localPosition = pos;
go.transform.localRotation = rot;
go.transform.localScale = scale;
go.name = gname;
go.SetActive(enable);
Debug.LogFormat("Replace Prefab From:{0} to {1}", oripath, tar);
}
}
代碼中主要的流程為
- 使用Selection.activeGameObject獲取選中的物體
- 使用PrefabUtility.GetPrefabParent獲取這個物體在project中的源prefab
- 使用AssetDatabase.GetAssetPath獲取源prefab在project中的路徑(后面用於log)
- 使用EditorUtility.OpenFilePanelWithFilters打開一個文件選擇窗口讓玩家選擇一個源prefab
- 使用FileUtil.GetProjectRelativePath獲取這個源prefab相對於工程的路徑
- 使用將這個源prefab加載到內存中
- 為了保持替換后的位置關系,這里記錄了原來的位置信息
- 使用PrefabUtility.ConnectGameObjectToPrefab重新將選中的物體鏈接到玩家選擇的源prefab上,完成prefab引用替換
- 還原原來的位置關系
至此完成了Prefab實例替換引用的功能。在Unity中選擇菜單Tools->Prefab->替換引用,選擇一個prefab即可實現替換
轉載保留:http://www.cnblogs.com/CodeGize http://www.codegize.com