大家知道, 在日常修改预制的时候很方便, 我们将预制从资源文件夹往场景上"一拖", 然后就可以进行修改, 然后应用保存即可.
但是如果某些需求下, 我们想要使用代码来完成这个操作就比较麻烦.
比如需求为: 查找某个文件夹下所有预制, 如果其中有使用了RectMask2D组件的, 需要全部替换成Mask, 并且在替换完成后需要人工确定是否正确.
如果不需要人工确定, 其实很简单, 配合AssetDataBase
相关的接口将预制加载出来, 然后替换组件后保存预制即可.
但是最后需要人工确定, 有问题还需要手动修改一部分, 那么就需要将预制加载到场景, 然后自动选中发生修改的节点来确定修改的正确.
按照正常的逻辑, 我可以像正常使用预制, 实例化对象的线路去思考, 但是实践下来发现, 加载到场景的是实例化之后的对象, 修改后无法应用保存, 和手动拖预制的结果不一致.
这时我们就需要使用另一个接口来达到目的了:
using UnityEditor;
// 将给定场景中的给定预制件实例化
// 第一个参数target是预制资源
// 第二个参数destinationScene是目标场景, 如果不传就默认是当前场景
public static Object PrefabUtility.InstantiatePrefab (Object target , SceneManagement.Scene destinationScene);
首先需要遍历选中目录, 查找预制并加载:
// Selection.activeObject是当前选中的目录
var dir = AssetDatabase.GetAssetPath(Selection.activeObject);
if (!Directory.Exists(dir))
{
Debug.LogError("选中的不是目录!" + dir);
return;
}
var allPrefabLst = AssetDatabase.FindAssets("t:Prefab", new []{dir});
foreach (var guid in allPrefabLst)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
var prefab = AssetDatabase.LoadAssetAtPath(path);
var find = go.GetComponentInChildren(true);
if (!find) continue;
// ...
}
预制实例化并加到场景后, 将返回的对象转换类型后就可以设置其父节点:
var obj = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
// 注意第二个参数, 如果不为false, 会导致加载出来的对象transform发生变化
obj.transform.SetParent(rootTransform, false);
我们还需要找到当前场景中指定的节点作为其统一挂载的父节点:
// 比如: 场景中的节点层级为: rootNode/xxx/parent
// 通过调用GetCurSceneObject("rootNode", "xxx/parent")完成需求
static GameObject GetCurSceneObject(string rootName, string selectPath)
{
var curScene = SceneManager.GetActiveScene();
foreach (var rootGameObject in curScene.GetRootGameObjects())
{
if (!rootName.Equals(rootGameObject.name)) continue;
var transform = rootGameObject.transform.Find(selectPath);
if (transform) return transform.gameObject;
}
return null;
}
然后是替换组件:
private static void ReplaceRectMask2D(GameObject go)
{
var children = rootGo.GetComponentsInChildren(true);
foreach (var rectMask2D in children)
{
var go = rectMask2D.gameObject;
// 非运行模式下需要使用这个接口
Object.DestroyImmediate(rectMask2D);
go.AddComponent();
}
}
最后选中对象可以使用这里的介绍.
下面是完整的代码:
[MenuItem("Assets/PrintRectMask2DReferences", priority = 301)]
private static void PrintRectMask2DReferences()
{
var dir = AssetDatabase.GetAssetPath(Selection.activeObject);
if (!Directory.Exists(dir))
{
Debug.LogError("选中的不是目录!" + dir);
return;
}
var allPrefabLst = AssetDatabase.FindAssets("t:Prefab", new []{dir});
var rootNode = GetCurSceneObject("rootNode", "xxx/parent");
if (!rootNode)
{
Debug.LogError("当前场景没有找到挂载节点: " + "rootNode/xxx/parent");
return;
}
var rootTransform = rootNode.transform;
var findLst = new List();
foreach (var guid in allPrefabLst)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
var prefab = AssetDatabase.LoadAssetAtPath(path);
var find = prefab.GetComponentInChildren(true);
if (!find) continue;
Debug.Log("find =>: " + path);
var go = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
if (!go) continue;
findLst.Add(go);
go.transform.SetParent(rootTransform, false);
ReplaceRectMask2D(go);
}
Debug.LogError("一共找到预制: " + findLst.Count);
}
好了, 以上就是今天的内容, 希望对大家有所帮助.