• Unity中的AssetBundle


    AssetBundle的概念

    AssetBundle又称AB包,是Unity提供的一种用于存储资源的资源压缩包,是对Unity 初始Resources的一种扩展;一般使用的策略是把必须的资源和不需要更新的资源放在Resources文件夹下,其他的资源放在AssetBundle下面。

    Unity中的AssetBundle系统是对资源管理的一种扩展,通过将资源分布在不同的AB包中可以最大程度地减少运行时的内存压力,可以动态地加载和卸载AB包,继而有选择地加载内容。

    AssetBundle的优势

    1. AB包存储位置自定义,继而可放入可读可写的路径下便于实现热更新。
    2. AB包自定义压缩方式,可以选择不压缩或选择LZMA和LZ4等压缩方式,减小包的大小,更快的进行网络传输。
    3. 资源可分布在不同的AB包中,最大程度减少运行时的内存压力, 可做到即用即加载,有选择的加载需要的内容。
    4. AB包支持后期进行动态更新,显著减小初始安装包的大小,非核心资源以AB包形式上传服务器,后期运行时动态加载,提高用户体验。

    AssetBundle和Resources的比较

    AssetBundleResources
    资源可分布在多个包中所有资源打包成一个大包
    存储位置自定义灵活必须存放在Resources目录下
    压缩方式灵活(LZMA,LZ4)资源全部会压缩成二进制
    支持后期进行动态更新打包后资源只读无法动态更改

    AssetBundle的特性

    1. AB包可以存储绝大部分Unity资源但无法直接存储C#脚本,所以代码的热更新需要使用Lua或者存储编译后的DLL文件。
    2. AB包不能重复进行加载,当AB包已经加载进内存后必须卸载后才能重新加载。
    3. 多个资源分布在不同的AB包可能会出现一个预制体的贴图等部分资源不在同一个包下,直接加载会出现部分资源丢失的情况,即AB包之间是存在依赖关系的,在加载当前AB包时需要一并加载其所依赖的包。
    4. 打包完成后,会自动生成一个主包(主包名称随平台不同而不同),主包的manifest下会存储有版本号、校验码(CRC)、所有其它包的相关信息(名称、依赖关系)

    AssetBundle全打包流程

    本次主要介绍Unity官方提供的AB包管理插件AssetBundle Browser 进行打包

    1. AssetBundleBrowser插件的获取 Unity 2019版本可以直接在Windows —>PackageManager里面找到此插件并直接安装
      在这里插入图片描述
    2. 2020版本之后或其它版本可能在1方法中找不到此插件,可以通过去github搜索下载压缩包,将下载后的安装包解压到Unity工程的Packages文件夹下 (一定要解压)

    AssetBundleBrowser面板的使用

    正确获取到并安装完插件后,通过 Windows ----> AssetBundle Browser下打开AB包管理面板 一共有三个面板

    Configure面板 :能查看当前AB包及其内部资源的基本情况(大小,资源,依赖情况等)

    在这里插入图片描述

    Build面板:负责AssetBundle打包的相关设置 按Build即可进行打包
    在这里插入图片描述

    三种压缩方式

    NoCompression:不压缩,解压快,包较大,不建议使用。
    LZMA: 压缩最小,解压慢,用一个资源要解压包下所有资源。
    LZ4: 压缩稍大,解压快,用什么解压什么,内存占用低,一般建议使用这种。
    一般需要进行更改的设置即为图中勾选的相关选项设置。

    Inspect面板:主要用来查看已经打包后的AB包文件的一些详细情况(大小,资源路径等)
    在这里插入图片描述
    3、设置资源所属的AssetBundle包

    在需要打包的资源的Inspector面板下方即可选择其应放在哪个AB包下,也可通过New新建AB包将资源放入,放入后再次Build打包即可将此资源打入相应的AB包中。

    AssetBundle加载和卸载的代码示例

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class ABLoadTest : MonoBehaviour
    {
        private Dictionary<string, AssetBundle> abCache;
        private AssetBundle mainAB = null; //主包
        private AssetBundleManifest mainManifest = null; //主包中配置文件---用以获取依赖包
                                                         
    
        private string basePath
        {
            get
            {
    #if UNITY_EDITOR || UNITY_STANDALONE
                return Application.dataPath + "/StreamingAssets/";
    #elif UNITY_IPHONE
                    return Application.dataPath + "/Raw/";
    #elif UNITY_ANDROID
                    return Application.dataPath + "!/assets/";
    #endif
            }
        }
    
        void Start()
        {
            abCache = new Dictionary<string, AssetBundle>();
    
            var ab = LoadABTest();
            GameObject model = ab.LoadAsset<GameObject>("Cube");
            var b = Instantiate<GameObject>(model);
            // dosomething
    
    
        }
    
        AssetBundle LoadABTest()
        {
            AssetBundle ab;
            string abName = "3dmodel.first";
            if (mainAB == null)
            {
                mainAB = AssetBundle.LoadFromFile(basePath + "StandaloneWindows");
                mainManifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
    
            }
            //根据manifest获取所有依赖包的名称 固定API
            string[] dependencies = mainManifest.GetAllDependencies(abName);
            //循环加载所有依赖包
            for (int i = 0; i < dependencies.Length; i++)
            {
                //如果不在缓存则加入
                if (!abCache.ContainsKey(dependencies[i]))
                {
                    //根据依赖包名称进行加载
                    ab = AssetBundle.LoadFromFile(basePath + dependencies[i]);
                    //注意添加进缓存 防止重复加载AB包
                    abCache.Add(dependencies[i], ab);
                }
            }
            //加载目标包 -- 同理注意缓存问题
            if (abCache.ContainsKey(abName))
            {
                Debug.Log($"have load {abName}");
                return abCache[abName];
            }
            else
            {
                ab = AssetBundle.LoadFromFile(basePath + abName);
                abCache.Add(abName, ab);
                Debug.Log($"new load {abName}");
                return ab;
            }
        }
    
        // Update is called once per frame
        void Update()
        {
            if(Input.GetKeyDown(KeyCode.A)) // 同步加载
            {
                var ab = LoadABTest();
                GameObject model = ab.LoadAsset<GameObject>("Cube");
                var b = Instantiate<GameObject>(model);
            }
            else if (Input.GetKeyDown(KeyCode.S))// 异步加载
            {
                var ab = LoadABTest();
                StartCoroutine(LoadResAsyncTest(ab));
                
            }
            else if (Input.GetKeyDown(KeyCode.D))// 单个卸载
            {
                UnLoad("3dmodel.first");
                Debug.Log("have UnLoadAll 3dmodel.first");
    
            }
            else if (Input.GetKeyDown(KeyCode.F))// 全部卸载
            {
                UnLoadAll();
                Debug.Log("have UnLoadAll");
            }
    
        }
    
        private IEnumerator LoadResAsyncTest(AssetBundle ab)
        {
            if (ab == null) yield return null;
            var model1 = ab.LoadAssetAsync<GameObject>("Cube");
            yield return model1;
            var async_model = Instantiate((GameObject)model1.asset);
            // dosomething
        }
    
        //====================AB包的两种卸载方式=================
        //单个包卸载
        public void UnLoad(string abName)
        {
            if (abCache.ContainsKey(abName))
            {
                abCache[abName].Unload(false);
                //注意缓存需一并移除
                abCache.Remove(abName);
            }
        }
    
        //所有包卸载
        public void UnLoadAll()
        {
            AssetBundle.UnloadAllAssetBundles(false);
            //注意清空缓存
            abCache.Clear();
            mainAB = null;
            mainManifest = null;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138

    参考资料:Unity中AB包详解(超详细,特性,打包,加载,管理器)

  • 相关阅读:
    DAOS学习笔记及思考
    java毕业设计乒乓球俱乐部管理源码+lw文档+mybatis+系统+mysql数据库+调试
    iOS开发之弹窗管理
    visual studio 启用DPI识别功能
    再写一遍的网络流
    Hadoop运行模式
    9月30日计算机视觉基础学习笔记——优化算法
    【基础教程】Matlab实现等高线图
    【异步VS多线程】异步VS多线程区别
    Gin框架中的Cookie怎么搞(会话控制)
  • 原文地址:https://blog.csdn.net/qq_41841073/article/details/127713666