大量生産されたプレハブを機械的にいじる機会がちょいちょいあるので書いてみた。
public class PrefabChanger
{
public static void ExecuteChange(List<string> targets, System.Action<GameObject> onChange)
{
if (onChange == null) return;
foreach (string path in targets)
{
var prefabAsset = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject;
if (prefabAsset == null) continue;
var prefab = PrefabUtility.InstantiatePrefab(prefabAsset) as GameObject;
if (prefab == null) continue;
onChange(prefab);
PrefabUtility.ReplacePrefab(prefab, prefabAsset); // 反映.
GameObject.DestroyImmediate(prefab);
}
}
// 子どものGameObjectを走査して処理を適用するためのヘルパ.
public static void ScanTree(GameObject gameObj, System.Action<GameObject> onExecute)
{
if (gameObj == null) return;
if (onExecute == null) return;
onExecute(gameObj);
if (gameObj.transform.childCount > 0)
{
for (int i = 0; i < gameObj.transform.childCount; ++i)
{
var child = gameObj.transform.GetChild(i);
ScanTree(child.gameObject, onExecute);
}
}
}
}
使い方
List<string> targets = new List<string>();
// ディレクトリパスを指定.
targets.Add("Assets/Prefabs/PrefabA.prefab");
targets.Add("Assets/Prefabs/PrefabB.prefab");
targets.Add("Assets/Resources/Prefabs/Prefab01.prefab");
targets.Add("Assets/Resources/Prefabs/Prefab02.prefab");
PrefabChanger.ExecuteChange(targets, prefab => {
// 新しい子ノードを追加してあげたりとか、
GameObject child = new GameObject();
child.transform.parent = prefab.transform;
// 要らなくなったコンポーネントを削除するとか、
PrefabChanger.ScanTree(prefab, gameObj => {
GameObject.DestroyImmediate(gameObj.GetComponent<Hoge>());
});
});