Unity笔记之AssetBundle打包和加载(场景和预制体)

需求:实现用AssetBundle打包和加载场景、预制体。
这是参照一位大佬的拿来改了一点,但是现在没找到大佬的文章,就先这样吧。

实现打AB包方法一:

打包工具AssetBundleBuilder.cs

using UnityEngine;
using UnityEditor;
using System.IO;

/// <summary>
/// 资源包打包工具
/// </summary>
public class AssetBundleBuilder : EditorWindow
{
    [MenuItem("打包/Windows/资源包和场景")]
    public static void BuildAbsAndScenesWindows()
    {
        AssetBundleBuilder assetBundleBuilder = EditorWindow.GetWindow<AssetBundleBuilder>();
        assetBundleBuilder.Show();

        //
    }
    static string outPath;
    private void OnGUI()
    {
        GUILayout.Space(10);
        GUI.skin.label.fontSize = 12;
        GUI.skin.label.alignment = TextAnchor.MiddleLeft;
        GUILayout.Label("AssetBundle文件名称:", GUILayout.MaxWidth(160));
        outPath = EditorGUILayout.TextField(outPath);
        EditorGUI.EndDisabledGroup();

        //string s = EditorGUILayout.TextArea("s");
        if (GUILayout.Button("开始打包场景和资源"))
        {
            BuildAbsAndScenes(BuildTarget.StandaloneWindows);
        }

        //GUILayout.EndVertical();

        //EndWindows();
    }

    [MenuItem("打包/Android/资源包和场景")]
    public static void BuildAbsAndScenesAndroid()
    {
        BuildAbsAndScenes(BuildTarget.Android);
    }

    [MenuItem("打包/IOS/资源包和场景")]
    public static void BuildAbsAndScenesIOS()
    {
        BuildAbsAndScenes(BuildTarget.iOS);
    }

    [MenuItem("打包/Windows/资源包")]
    public static void BuildAbsWindows()
    {
        BuildAssetBundles(BuildTarget.StandaloneWindows);
    }

    [MenuItem("打包/Android/资源包")]
    public static void BuildAbsAndroid()
    {
        BuildAssetBundles(BuildTarget.Android);
    }

    [MenuItem("打包/IOS/资源包")]
    public static void BuildAbsIOS()
    {
        BuildAssetBundles(BuildTarget.iOS);
    }

    [MenuItem("打包/Windows/场景")]
    public static void BuildScenesWindows()
    {
        BuildScenes(BuildTarget.StandaloneWindows);
    }

    [MenuItem("打包/Android/场景")]
    public static void BuildScenesAndroid()
    {
        BuildScenes(BuildTarget.Android);
    }

    [MenuItem("打包/IOS/场景")]
    public static void BuildScenesIOS()
    {
        BuildScenes(BuildTarget.iOS);
    }

    // 打包AssetBundle和Scenes
    public static void BuildAbsAndScenes(BuildTarget platform)
    {
        BuildAssetBundles(platform);
        BuildScenes(platform);
    }

    // 打包AssetBundles
    private static void BuildAssetBundles(BuildTarget platform)
    {
        // 输出路径
        //string outPath = Application.streamingAssetsPath + "/Abs";
        if (!Directory.Exists(outPath)) Directory.CreateDirectory(outPath);
        EditorUtility.DisplayProgressBar("信息", "打包资源包", 0f);
        BuildPipeline.BuildAssetBundles(outPath, BuildAssetBundleOptions.DeterministicAssetBundle, platform);
        AssetDatabase.Refresh();
        Debug.Log("所有资源包打包完毕");
    }

    // 打包Scenes
    private static void BuildScenes(BuildTarget platform)
    {
        // 指定场景文件夹和输出路径
        string scenePath = Application.dataPath + "/AbResources/Scenes";
        //string outPath = Application.streamingAssetsPath + "/Abs/";

        if (Directory.Exists(scenePath))
        {
            // 创建输出文件夹
            if (!Directory.Exists(outPath)) Directory.CreateDirectory(outPath);

            // 查找指定目录下的场景文件
            string[] scenes = GetAllFiles(scenePath, "*.unity");
            for (int i = 0; i < scenes.Length; i++)
            {
                string url = scenes[i].Replace("\\", "/");
                int index = url.LastIndexOf("/");
                string scene = url.Substring(index + 1, url.Length - index - 1);
                string msg = string.Format("打包场景{0}", scene);
                EditorUtility.DisplayProgressBar("信息", msg, 0f);
                scene = scene.Replace(".unity", ".scene");
                Debug.Log(string.Format("打包场景{0}到{1}", url, outPath + scene));
                BuildPipeline.BuildPlayer(scenes, outPath + scene, BuildTarget.StandaloneWindows, BuildOptions.BuildAdditionalStreamedScenes);
                AssetDatabase.Refresh();
            }
            EditorUtility.ClearProgressBar();
            Debug.Log("所有场景打包完毕");
        }
    }

    /// <summary> 获取文件夹和子文件夹下所有指定类型文件 </summary>
    private static string[] GetAllFiles(string directory, params string[] types)
    {
        if (!Directory.Exists(directory)) return new string[0];
        string searchTypes = (types == null || types.Length == 0) ? "*.*" : string.Join("|", types);
        string[] names = Directory.GetFiles(directory, searchTypes, SearchOption.AllDirectories);
        return names;
    }

}

加载ABTest.cs

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class ABTest : MonoBehaviour
{

    public Text textProgress;
    private void Awake()
    {
        //DontDestroyOnLoad(gameObject);
        //StartCoroutine(DownloadPrefab());
        //StartCoroutine(DownloadScene());

        LoadScene(Application.streamingAssetsPath + "/Abs/" + "test");
        LoadPrefabs(Application.streamingAssetsPath + "/Abs/" + "cube.ab");
    }
    public void LoadPrefabs(string url)
    {
        StartCoroutine(DownloadPrefab(url));
    }
    IEnumerator DownloadPrefab(string url)
    {
        //ab包的地址
        //string url = Application.streamingAssetsPath + "/Abs/" + "cube" + ".ab";
        AssetBundle ab;
        using (UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url))
        {
            //yield return request.SendWebRequest();
            request.SendWebRequest();
            while (!request.isDone)
            {
                Debug.Log(request.downloadProgress);
                //textProgress.text = (request.downloadProgress * 100).ToString("F0") + "%";
                yield return null;
            }
            if (request.isDone)
            {
                Debug.Log(100);
                //textProgress.text = 100 + "%";
            }
            ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
            if (ab == null)
            {
                Debug.LogError("AB包为空");
                yield break;
            }

        }
        GameObject ga = ab.LoadAsset<GameObject>("Assets/Prefabs/cube.prefab");//加载出来
        Instantiate<GameObject>(ga);//实例化出来

        //Debug.Log(ga.name);
        //ab.Unload(false); 
        Debug.Log("成功");
        yield break;
    }

    public void LoadScene(string url)
    {
        StartCoroutine(DownloadScene(url));
    }
    IEnumerator DownloadScene(string url)
    {

        //ab包的地址
        //string url = Application.streamingAssetsPath + "/Abs/" + "samplescene";

        //方式一
        //AssetBundle ab;
        //using (UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url))
        //{
        //    //yield return request.SendWebRequest();
        //    request.SendWebRequest();
        //    while (!request.isDone)
        //    {
        //        Debug.Log(request.downloadProgress);
        //        //textProgress.text = (request.downloadProgress * 100).ToString("F0") + "%";
        //        yield return null;
        //    }
        //    if (request.isDone)
        //    {
        //        Debug.Log(100);
        //        //textProgress.text = 100 + "%";
        //    }
        //    ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
        //    if (ab == null)
        //    {
        //        Debug.LogError("AB包为空");
        //        yield break;
        //    }
        //    string[] s = ab.GetAllScenePaths();
        //    SceneManager.LoadScene(s[0], LoadSceneMode.Single);
        //}

        //方式二
        myLoadedAssetBundle = AssetBundle.LoadFromFile(url);
        scenePaths = myLoadedAssetBundle.GetAllScenePaths();
        SceneManager.LoadScene(scenePaths[0], LoadSceneMode.Single);

        Debug.Log("成功");
        yield break;
    }
    private AssetBundle myLoadedAssetBundle;
    private string[] scenePaths;
}


这里面的加载场景有两种方式,但是最关键、核心的就是这句代码
scenePaths = myLoadedAssetBundle.GetAllScenePaths();

以上就是打包和加载了
但是这样的打包存在一定的局限性,不太建议使用这种方式。还有一种方式就是使用官方的AssetBundleBrowser来进行打包和加载(也是个人比较推荐的)。

实现打AB包方法二:

1、去PackageManager里面下载Asset Bundle Browser;
2、打开Asset Bundle Browser窗口;
在这里插入图片描述
3、把资源拖进去
在这里插入图片描述
(这里报感叹号弄成依赖资源就可以去掉了,当然也可以不管)
在这里插入图片描述
然后build根据个人需求修改就可以打包了
在这里插入图片描述
至此,打包结束。

然后就是加载资源:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

public class DemoLoadBundle : MonoBehaviour
{
    public string bundleName = "dogpbr";//预制体ab的名字
    public string assetName = "dogpbr";//加载到场景中这个物体的名字

    private void Start()
    {
        DontDestroyOnLoad(gameObject);

        LoadDependencies();

        LoadBundleScene();
    }
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            InstantiateBundlePrefab();
        }
    }
    /// <summary>
    /// 保存所有AssetBundle包的物体的名字
    /// </summary>
    public List<string> abPrefabNameList = new List<string>();
    /// <summary>
    /// 保存所有AssetBundle包场景的名字
    /// </summary>
    public List<string> abSceneNameList = new List<string>();


    /// <summary>
    /// 加载所有依赖资源(这里记录的只是单个场景和单个预制体的演示)
    /// </summary>
    void LoadDependencies()
    {
        //AssetBundleManifest 记录着所有资源的依赖信息
        AssetBundle assetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/StandaloneWindows");
        AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

        //获取所有ab资源的名字
        string[] s = manifest.GetAllAssetBundles();
        for (int i = 0; i < s.Length; i++)
        {
            if (Check(s[i])||s[i].Contains("new")) continue;

            if (s[i].Contains("scene")) abSceneNameList.Add(s[i]);
            else abPrefabNameList.Add(s[i]);

            Debug.Log(s[i]);
        }

        //加载预制体的依赖包
        string[] dependenciesPrefab = manifest.GetAllDependencies(bundleName);
        foreach (var dependencie in dependenciesPrefab)
        {
            var dependencieAsync = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + dependencie);
        }

        //加载场景的依赖包
        string[] dependencieScene = manifest.GetAllDependencies(sceneName);
        foreach (var dependencie in dependencieScene)
        {
            var dependencieAsync = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + dependencie);
        }
    }
    private bool Check(string name)
    {
        if (abPrefabNameList.Contains(name)) return true;
        if (abSceneNameList.Contains(name)) return true;
        return false;
    }

    AssetBundle asset;//实现可多次加载
    /// <summary>
    /// 加载ab包的预制体(单个)
    /// </summary>
    private void InstantiateBundlePrefab()
    {
        if (asset == null)
            asset = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + bundleName);
        var asset_go = asset.LoadAsset<GameObject>(assetName);
        Instantiate(asset_go);
    }

    public string sceneName = "abtestscene";//场景打包出来的名字
    #region 方式一
    /// <summary>
    /// 加载ab包的场景(单个)
    /// 注:加载场景的时候可能会出现一个问题,那就是场景里面存在一个ab包的预制体,但你再去加载这个预制体就会报错。(解决办法就是把你场景里面的那个预制体删掉就可以了)
    /// </summary>
    IEnumerator LoadABScene()
    {
        AssetBundle ab;
        using (UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(""))
        {
            //yield return request.SendWebRequest();
            request.SendWebRequest();
            while (!request.isDone)
            {
                Debug.Log(request.downloadProgress);
                //textProgress.text = (request.downloadProgress * 100).ToString("F0") + "%";
                yield return null;
            }
            if (request.isDone)
            {
                Debug.Log(100);
                //textProgress.text = 100 + "%";
            }
            ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
            if (ab == null)
            {
                Debug.LogError("AB包为空");
                yield break;
            }
            string[] s = ab.GetAllScenePaths();
            SceneManager.LoadScene(s[0], LoadSceneMode.Single);
        }
    }
    #endregion

    #region 方式二
    /// <summary>
    /// 加载ab包的场景(单个)
    /// 注:加载场景的时候可能会出现一个问题,那就是场景里面存在一个ab包的预制体,但你再去加载这个预制体就会报错。(解决办法就是把你场景里面的那个预制体删掉就可以了)
    /// </summary>
    private void LoadBundleScene()
    {
        myLoadedAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + sceneName);
        scenePaths = myLoadedAssetBundle.GetAllScenePaths();
        SceneManager.LoadScene(scenePaths[0], LoadSceneMode.Single);
    }
    private AssetBundle myLoadedAssetBundle;
    private string[] scenePaths;
    #endregion
}

以上就是一整套的打包和加载了。

方法三:

因为第一种没测试过是否会把预制体的依赖资源一起打进去,所以才有了这第三种方法的记录。
Editor目录下的打包脚本: CreateAssetBundles.cs(对了,这个方法预制体打标签时不能有后缀,只能有名字)

using UnityEditor;
using System.IO;

public class CreateAssetBundles 
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAssetBundles()
    {
        string dir = "AssetBundles";
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }

        BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
    }
    
}

这个路径是打包到Asset同一层级的目录下,加载测试脚本里面的路径是StreamingAssets目录下,所以需自行拖到StreamingAssets目录下。
加载脚本:DownLoadAssetBundles.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DownLoadAssetBundles : MonoBehaviour
{
 
    void Start()
    {
        InstantiateBundlePrefab();
    }

    public string assetName;
    AssetBundle asset;//实现可多次加载
    /// <summary>
    /// 加载ab包的预制体(单个)
    /// </summary>
    private void InstantiateBundlePrefab()
    {
        if (asset == null)
            asset = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + assetName);
        var asset_go = asset.LoadAsset<GameObject>(assetName);
        Instantiate(asset_go);
    }
}

以上就是方法三的打包和加载了。

posted @   一世癫狂  阅读(52)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示