Unity中使用代码将预制加载到场景

Posted 拂面清风三点水

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity中使用代码将预制加载到场景相关的知识,希望对你有一定的参考价值。

Unity中使用代码将预制加载到场景

大家知道, 在日常修改预制的时候很方便, 我们将预制从资源文件夹往场景上"一拖", 然后就可以进行修改, 然后应用保存即可.

但是如果某些需求下, 我们想要使用代码来完成这个操作就比较麻烦.

比如需求为: 查找某个文件夹下所有预制, 如果其中有使用了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<GameObject>(path);
    var find = go.GetComponentInChildren<RectMask2D>(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<RectMask2D>(true);
    foreach (var rectMask2D in children)
    
        var go = rectMask2D.gameObject;
        
        // 非运行模式下需要使用这个接口
        Object.DestroyImmediate(rectMask2D);
        go.AddComponent<Mask>();
    

最后选中对象可以使用这里的介绍.

下面是完整的代码:

[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<GameObject>();
    foreach (var guid in allPrefabLst)
    
        var path = AssetDatabase.GUIDToAssetPath(guid);
        var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
        var find = prefab.GetComponentInChildren<RectMask2D>(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);

好了, 以上就是今天的内容, 希望对大家有所帮助.

unity 3d发布的exe程序可以从外部(比如同文件夹下的一个fbx文件)读取模型到场景中吗?

目的是动态的读取文件,而不用重新发布exe程序

参考技术A 使用AssetBundles让你通过WWW类流式加载额外的资源并在运行时实例化它们
使用方式可以看看雨凇momo的这篇博文:
http://www.xuanyusong.com/archives/2405本回答被提问者和网友采纳

以上是关于Unity中使用代码将预制加载到场景的主要内容,如果未能解决你的问题,请参考以下文章

在 Unity3d 中将游戏对象动态添加到场景中

unity 3d发布的exe程序可以从外部(比如同文件夹下的一个fbx文件)读取模型到场景中吗?

如何用Unity 和Vuforia 创建一款AR应用

使用 Unity 在游戏期间随时加载 .fbx 对象

Unity运行时代码编辑插件介绍-InGame Code Editor-IDE类文本编辑器

Unity运行时代码编辑插件介绍-InGame Code Editor-IDE类文本编辑器