45.PrefabUtility
45.1 知识点
PrefabUtility公共类是什么
它是 Unity 编辑器中的一个公共类,提供了一些用于处理 Prefab(预制体或称预设体)的方法。主要功能包括实例化预制体、创建预制体、修改预制体等等。只要你有对预制体操作的相关需求,它可以在编辑器开发的任何地方对其进行使用。
创建自定义面板用于进行知识讲解
using UnityEditor;
using UnityEngine;
public class MyPrefabUtilityLearnWindow : EditorWindow
{
    [MenuItem("编辑器拓展教程/MyPrefabUtilityLearnWindow")]
    private static void OpenMyPrefabUtilityLearnWindow()
    {
        MyPrefabUtilityLearnWindow win = EditorWindow.GetWindow<MyPrefabUtilityLearnWindow>("PrefabUtility知识学习");
        win.Show();
    }
    private void OnGUI()
    {
        
    }
}
常用API
动态创建预设体
private void OnGUI()
{
    // 动态创建预设体 路径从Assets/...开始
    // PrefabUtility.SaveAsPrefabAsset(GameObject对象, 路径);
    if (GUILayout.Button("动态创建预设体"))
    {
        GameObject obj = new GameObject();//场景上也会出现预制体
        obj.AddComponent<Rigidbody>();
        obj.AddComponent<BoxCollider>();
        PrefabUtility.SaveAsPrefabAsset(obj, "Assets/Resources/TestObj.prefab");
        DestroyImmediate(obj);//不想场景上也出现预制体就立即删除
    }
}

加载预制体对象(不能用于创建,一般用于修改,会把预设体加载到内存中)
private void OnGUI()
{
    // 加载预制体对象(不能用于创建,一般用于修改,会把预设体加载到内存中)
    // 路径从Assets/...开始
    // PrefabUtility.LoadPrefabContents(路径)
    // 释放加载的预设体对象
    // PrefabUtility.UnloadPrefabContents(GameObject对象)
    // 注意:这两个方法需要配对使用,加载了就要释放
    // 这里的加载 本质上其实已经把预设体进行了实例化了 只不过该实例化对象并不是在传统的Scene窗口中(是在一个看不见的独立的场景中)
    if (GUILayout.Button("加载预制体对象"))
    {
        // 加载 到内存中 不能用来实例化 一般加载出来是进行修改的  比如给预制体添加组件
        GameObject testObj = PrefabUtility.LoadPrefabContents("Assets/Resources/TestObj.prefab");
        testObj.AddComponent<MeshRenderer>();
        // 拓展:
        // 这种加载方式 是可以进行脚本移除 子对象创建的
        DestroyImmediate(testObj.GetComponent<MeshRenderer>());
        GameObject obj = new GameObject("新建子对象");
        obj.transform.parent = testObj.transform;
        // 覆盖了原先的预制体
        PrefabUtility.SaveAsPrefabAsset(testObj, "Assets/Resources/TestObj.prefab");
        // 释放 一定要配合使用
        PrefabUtility.UnloadPrefabContents(testObj);
    }
}


修改已有预设体
private void OnGUI()
{
    // 修改已有预设体 
    // PrefabUtility.SavePrefabAsset(预设体对象, out bool 是否保存成功);
    // 可以配合AssetDatabase.LoadAssetAtPath使用
    if (GUILayout.Button("修改已有预设体 "))
    {
        GameObject testObj = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Resources/TestObj.prefab");
        testObj.AddComponent<Camera>();
        // 这个方法不能存储实例化后的内容 只能存储对应的预设体对象
        PrefabUtility.SavePrefabAsset(testObj);
    }
}

实例化预设体
private void OnGUI()
{
    // 实例化预设体
    // PrefabUtility.InstantiatePrefab(Object对象)
    if (GUILayout.Button("实例化预设体"))
    {
        GameObject testObj = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Resources/TestObj.prefab");
        PrefabUtility.InstantiatePrefab(testObj);
    }
}

更多内容
官方文档:PrefabUtility
45.2 知识点代码
Lesson45_PrefabUtility
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson45_PrefabUtility : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 PrefabUtility公共类是什么
        //它是 Unity 编辑器中的一个公共类
        //提供了一些用于处理 Prefab(预制体或称预设体)的方法
        //主要功能包括 实例化预制体、创建预制体、修改预制体 等等
        //只要你有对预制体操作的相关需求
        //它可以在编辑器开发的任何地方对其进行使用
        #endregion
        #region 知识点二 创建自定义面板用于进行知识讲解
        #endregion
        #region 知识点三 常用API
        //1.动态创建预设体 路径从Assets/...开始
        //  PrefabUtility.SaveAsPrefabAsset(GameObject对象, 路径);
        //2.加载预制体对象(不能用于创建,一般用于修改,会把预设体加载到内存中)
        //  路径从Assets/...开始
        //  PrefabUtility.LoadPrefabContents(路径)
        //  释放加载的预设体对象
        //  PrefabUtility.UnloadPrefabContents(GameObject对象)
        //  注意:这两个方法需要配对使用,加载了就要写在
        //3.修改已有预设体 
        //  PrefabUtility.SavePrefabAsset(预设体对象, out bool 是否保存成功);
        //  可以配合AssetDatabase.LoadAssetAtPath使用
        //4.实例化预设体
        //  PrefabUtility.InstantiatePrefab(Object对象)
        #endregion
        #region 知识点四 更多内容
        //官方文档:https://docs.unity3d.com/2022.3/Documentation/ScriptReference/PrefabUtility.html
        #endregion
    }
}
MyPrefabUtilityLearnWindow
using System;
using UnityEditor;
using UnityEngine;
public class MyPrefabUtilityLearnWindow : EditorWindow
{
    [MenuItem("编辑器拓展教程/MyPrefabUtilityLearnWindow")]
    private static void OpenMyPrefabUtilityLearnWindow()
    {
        MyPrefabUtilityLearnWindow win = EditorWindow.GetWindow<MyPrefabUtilityLearnWindow>("PrefabUtility知识学习");
        win.Show();
    }
    private void OnGUI()
    {
        //1.动态创建预设体 路径从Assets/...开始
        //  PrefabUtility.SaveAsPrefabAsset(GameObject对象, 路径);
        if (GUILayout.Button("动态创建预设体"))
        {
            GameObject obj = new GameObject();//场景上也会出现预制体
            obj.AddComponent<Rigidbody>();
            obj.AddComponent<BoxCollider>();
            PrefabUtility.SaveAsPrefabAsset(obj, "Assets/Resources/TestObj.prefab");
            DestroyImmediate(obj);//不想场景上也出现预制体就立即删除
        }
        
        //2.加载预制体对象(不能用于创建,一般用于修改,会把预设体加载到内存中)
        //  路径从Assets/...开始
        //  PrefabUtility.LoadPrefabContents(路径)
        //  释放加载的预设体对象
        //  PrefabUtility.UnloadPrefabContents(GameObject对象)
        //  注意:这两个方法需要配对使用,加载了就要释放
        //这里的加载 本质上其实已经把预设体进行了实例化了 只不过该实例化对象并不是在传统的Scene窗口中(是在一个看不见的独立的场景中)
        if (GUILayout.Button("加载预制体对象"))
        {
            //加载 到内存中 不能用来实例化 一般加载出来是进行修改的  比如给预制体添加组件
            GameObject testObj = PrefabUtility.LoadPrefabContents("Assets/Resources/TestObj.prefab");
            testObj.AddComponent<MeshRenderer>();
            
            //拓展:
            //这种加载方式 是可以进行脚本移除 子对象创建的
            DestroyImmediate(testObj.GetComponent<MeshRenderer>());
            GameObject obj = new GameObject("新建子对象");
            obj.transform.parent = testObj.transform;
            
            
            //覆盖了原先的预制体
            PrefabUtility.SaveAsPrefabAsset(testObj, "Assets/Resources/TestObj.prefab");
            //释放 一定要配合使用
            PrefabUtility.UnloadPrefabContents(testObj);
        }
        
        //3.修改已有预设体 
        //  PrefabUtility.SavePrefabAsset(预设体对象, out bool 是否保存成功);
        //  可以配合AssetDatabase.LoadAssetAtPath使用
        if (GUILayout.Button("修改已有预设体 "))
        {
            GameObject testObj = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Resources/TestObj.prefab");
            testObj.AddComponent<Camera>();
            //这个方法不能存储实例化后的内容 只能存储对应的预设体对象
            PrefabUtility.SavePrefabAsset(testObj);
        }
        
        //4.实例化预设体
        //  PrefabUtility.InstantiatePrefab(Object对象)
        if (GUILayout.Button("实例化预设体"))
        {
            GameObject testObj = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Resources/TestObj.prefab");
            PrefabUtility.InstantiatePrefab(testObj);
        }
    }
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com
 
            