首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Unity一键制作预制体Prefab一键修改Prefab属性

Unity一键制作预制体Prefab一键修改Prefab属性

作者头像
心疼你的一切
发布2026-01-20 13:34:53
发布2026-01-20 13:34:53
1920
举报
文章被收录于专栏:人工智能人工智能

👉一.一键生成多个预制体的方法

👉1.1 适用于制作多个预制体(一个模型文件下面几百个子物体,都需要制作成预制体,这一个一个拖不是要炸裂)

👉1.2 模型资源如下图

请添加图片描述
请添加图片描述

👉1.3 模型先放到Resources文件夹下面方便读取,制作完预制体可以给他拖到其他文件夹

模型文件结构如下图(经测试放模型的文件夹名字要和模型名字一致,不然找不到,你也可以修改代码测试其他方法)

请添加图片描述
请添加图片描述

👉1.4 下面是编辑器脚本

代码语言:javascript
复制
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
/// <summary>
/// 编辑器脚本
/// </summary>

public class CreationPrefab : EditorWindow
{
    [MenuItem("Tools/一键生成Prefab")]
    public static void CreatePrefabWindow()
    {
        EditorWindow window = EditorWindow.GetWindowWithRect(typeof(CreationPrefab), new Rect(Screen.width / 3, Screen.height / 3, 800, 500), true, "CreationPrefab");
        window.Show();
    }
    //保存prefab的路径
    private static string toSavePrefabPath = "Assets/Prefabs/新模型库/机柜内设备";


    private void OnGUI()
    {

        EditorGUILayout.LabelField("预制体保存路径::", toSavePrefabPath, GUILayout.Width(110));
        toSavePrefabPath = EditorGUILayout.TextArea(toSavePrefabPath, GUILayout.Width(250));

        if (GUILayout.Button("转换预制体", GUILayout.Width(260)))
        {
            ToPrefab();
        }

        if (GUILayout.Button("修改预制体", GUILayout.Width(260)))
        {          
            ModifyPrefab(toSavePrefabPath);
        }

    }
    private void ToPrefab()
    {
        string path = "Assets/Resources";
        string[] allFolder1 = GetAllFolder(path);
        if (allFolder1 == null)
            return;
        //循环次数取决于 ,源文件的目录结构 ,此处为 4 级结构  
        //也就是Resources下面4级文件夹,到达模型文件夹  一级一个for循环
        for (int i = 0; i < allFolder1.Length; i++)
        {
            string path2 = $"{path}/{allFolder1[i]}";
            string[] allFolder2 = GetAllFolder(path2);
            if (allFolder2 == null)
            {
                return;
            }
            for (int j = 0; j < allFolder2.Length; j++)
            {
                string path3 = $"{path2}/{allFolder2[j]}";
                string[] allFolder3 = GetAllFolder(path3);
                if (allFolder3 == null)
                    return;
                for (int k = 0; k < allFolder3.Length; k++)
                {

                    string path4 = $"{path3}/{allFolder3[k]}";
                    string[] allFolder4 = GetAllFolder(path4);
                    Debug.Log($"编号:{k}     {allFolder3[k]}文件下有        {allFolder4.Length}       个文件夹!");
                    if (allFolder4 == null)
                        return;

                    if (!Directory.Exists(toSavePrefabPath))
                    {
                        Directory.CreateDirectory(toSavePrefabPath);
                    }

                    for (int l = 0; l < allFolder4.Length; l++)
                    {
                        string speedTree = $"{path4}/{allFolder4[l]}/{allFolder4[l]}";
                        string[] strs = Regex.Split(speedTree, path + "/", RegexOptions.IgnoreCase);
                        GameObject go = Instantiate(GetFileObj(strs[1]));
                        go.name = go.name.Replace("(Clone)", string.Empty);
                        //给预制体添加脚本,修改属性
                        //go.transform.tag = "Model";
                        //if (go.GetComponent<BoxCollider>() == null)
                        //    go.AddComponent<BoxCollider>();

                        //if (go.GetComponent<Rigidbody>() == null)
                        //    go.AddComponent<Rigidbody>();

                        //go.GetComponent<Rigidbody>().isKinematic = true;

                        string modeName = allFolder4[l].Split('_')[0];


                        for (int p = 0; p < go.transform.childCount; p++)
                        {
                            PrefabUtility.SaveAsPrefabAsset(go.transform.GetChild(p).gameObject, $"{toSavePrefabPath}/{go.transform.GetChild(p).name}.prefab");


                        }

                        DestroyImmediate(go);


                    }
                    AssetDatabase.Refresh();
                }
            }

        }

    }

    /// <summary>
    /// 获取路径下的 Obj
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private GameObject GetFileObj(string path)
    {
        GameObject go = Resources.Load<GameObject>(path);
        if (go != null)
        {
            return go;
        }
        else
        {
            Debug.Log(path);
            return null;
        }

    }
    /// <summary>
    /// 获取路径下的所有文件夹
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private string[] GetAllFolder(string path)
    {
        try
        {

            string[] dirs = Directory.GetDirectories(path, "*");
            string[] folderName = new string[dirs.Length];
            for (int i = 0; i < dirs.Length; i++)
            {
                string file = dirs[i].Split('\\')[1];
                folderName[i] = file;
            }
            return folderName;
        }
        catch (System.Exception)
        {

            return null;
        }


    }

    /// <summary>
    /// 修改预制体
    /// </summary>
    /// <param name="path"></param>
    private void ModifyPrefab(string path)
    {
       
        //获取文件下所有预制体文件
        DirectoryInfo info = new DirectoryInfo(path);
        FileInfo[] fileInfos = info.GetFiles("*.prefab");       
        List<GameObject> prefabs = new List<GameObject>();
        foreach (var item in fileInfos)
        {
            string paths = $"{path}/{item.Name}";
            GameObject prefab = AssetDatabase.LoadAssetAtPath(paths, typeof(GameObject)) as GameObject;
            prefabs.Add(prefab);
        }
        Debug.Log("执行么" + prefabs.Count);
        //修改属性
        for (int i = 0; i < prefabs.Count; i++)
        {           
            //修改预制体的position和旋转角度
            if (prefabs[i].GetComponent<Transform>() != null)
            {
                prefabs[i].GetComponent<Transform>().position = Vector3.zero;
                prefabs[i].GetComponent<Transform>().rotation = Quaternion.Euler(Vector3.zero);
            }
            //其他属性请自行添加即可
            //if (prefabs[i].GetComponent<Rigidbody>() != null)
            //{
            //    prefabs[i].GetComponent<Rigidbody>().isKinematic = false;
            //    PrefabUtility.SavePrefabAsset(prefabs[i]);
            //}

        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
}

👉1.5两个功能一个生成预制体,一个修改预制体的坐标和角度为0

👉1.6功能显示位置如下图

请添加图片描述
请添加图片描述

👉二. 编辑器脚本必须放到Editor文件夹下面,否则会报错的

👉实现原理

  1. 一键制作预制体 原理:通过脚本将场景中的选中对象(GameObject)自动保存为预制体资源。 关键API:PrefabUtility.SaveAsPrefabAsset 流程: 获取选中的场景对象。 指定预制体保存路径。 调用API生成预制体文件。
  2. 一键修改预制体属性 原理:批量加载所有预制体资源,通过反射或序列化修改指定属性。 关键API: AssetDatabase.LoadAssetAtPath:加载预制体资源。 PrefabUtility.SavePrefabAsset:保存修改后的预制体。

流程:

遍历项目中的预制体文件。

加载每个预制体并实例化到内存。

修改指定组件的属性(如Transform、自定义脚本参数)。

应用修改到原始预制体。

👉注意事项

  1. 资源管理 路径规范:预制体保存路径需符合Unity资源规范(如必须在Assets目录下)。 依赖处理:若预制体引用其他资源(如材质、脚本),需确保依赖项存在,避免引用丢失。 版本控制:批量修改前提交代码库,防止误操作导致资源不可逆损坏。
  2. 性能优化 分批处理:修改上千个预制体时,分帧处理(EditorCoroutine)避免编辑器卡死。 缓存机制:频繁操作时缓存AssetDatabase状态,减少重复加载开销。 过滤逻辑:通过名称或标签过滤目标预制体,避免无意义遍历。
  3. 修改逻辑安全 属性存在性检查:修改前验证组件是否存在,避免NullReferenceException。
代码语言:javascript
复制
if (instance.GetComponent<Rigidbody>() != null) {
    instance.GetComponent<Rigidbody>().mass = 10;
}

撤销支持:集成Undo.RecordObject支持操作回退。

代码语言:javascript
复制
Undo.RecordObject(prefab, "Modify Prefab Scale");
  1. 嵌套预制体与变体 嵌套处理:若使用嵌套预制体(Nested Prefab),需递归修改子预制体。

变体兼容:修改基预制体时,其变体(Variant)可能继承变更,需测试兼容性。

  1. 脚本兼容性 序列化规则:只有标记为[SerializeField]或public的字段才能被脚本修改。

自定义编辑器:若属性通过CustomEditor控制,需调用EditorUtility.SetDirty标记修改。

👉总结

本次总结的就是Unity一键制作预制体Prefab一键修改Prefab属性,有需要会继续添加新的 如能帮助到你,就帮忙点个赞吧,三连更好哦,谢谢 你的点赞就是对博主的支持,有问题记得留言评论哦! 不定时更新Unity开发技巧,觉得有用记得一键三连哦。么么哒

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 👉一.一键生成多个预制体的方法
    • 👉1.1 适用于制作多个预制体(一个模型文件下面几百个子物体,都需要制作成预制体,这一个一个拖不是要炸裂)
    • 👉1.2 模型资源如下图
    • 👉1.3 模型先放到Resources文件夹下面方便读取,制作完预制体可以给他拖到其他文件夹
    • 👉1.4 下面是编辑器脚本
    • 👉1.5两个功能一个生成预制体,一个修改预制体的坐标和角度为0
    • 👉1.6功能显示位置如下图
  • 👉二. 编辑器脚本必须放到Editor文件夹下面,否则会报错的
  • 👉实现原理
  • 👉注意事项
  • 👉总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档