• Unity3D学习笔记(二十九):AssetBundle


    AssetBundle
    什么是AssetBundle?
    AssetBundle是把一些资源文件或场景文件,以某种方式保存在一个文件中。一个AssetBundle可以包含模型、材质、图片或场景等。但是AssetBundle不能包含脚本文件。(脚本打包时需要编译,界面逻辑的热更新依赖Lua)
    AssetBundle主要用于做热更新使用。
     
    如何创建AB包
    第一个参数:
    ----无
    ----新建
    ----删除未使用的AssetBundle
    第二个参数:
    ----后缀:做资源高清和标清的区分,不能做资源AB包的区分
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEditor;
    public class CreateAssetBundle : MonoBehaviour {
        [MenuItem("AssetBundle/CreateAB")]
        static void CreateAB()
        {
            //第一个参数:AB包的输出路径
            //第二个参数:打包的参数设置,我们设置的是强制性的重新打包
            //第三个参数:AB包的适用平台,不同的平台使用的AB包是不一样的
            BuildPipeline.BuildAssetBundles(
                Application.streamingAssetsPath + "/AssetBundle/",
                BuildAssetBundleOptions.ForceRebuildAssetBundle,
                BuildTarget.StandaloneWindows64
                );
        }
    }
     
    .meta文件:记录该资源在Unity里的相关设置(配置信息表)
    作用:SVN团队合作时,同时更新资源和.meta文件
     
    如何使用AB包里的文件
    注意:避免在一个AB包里出现同名同类型文件,只会加载其中一个
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    public class LoadABTexture : MonoBehaviour {
        private Image image;
        private void Awake()
        {
            image = GetComponent<Image>();
        }
        // Use this for initialization
        void Start () {
            //要是AB包中的资源文件
            //第一种方式:先加载AB包
            //AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/ui");
            //第二种方式:
            WWW www = new WWW("file://" + Application.streamingAssetsPath + "/AssetBundle/ui");
            AssetBundle ab = www.assetBundle;
            Sprite sp = ab.LoadAsset<Sprite>("beijing_02.jpg");
            image.sprite = sp;
            image.SetNativeSize();
        }
    }
     
    打包加载Json.txt文件
    AssetBundle jsonAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/json");
    TextAsset json = jsonAB.LoadAsset<TextAsset>("Json");
    Debug.Log(json);
     
    打包加载预制体
    AB包的依赖性
    如果一个AB包a中的资源,使用了另一个AB包b中的资源,那么这个a就依赖于b。
    当你使用AB包a中的资源的时候,需要先把依赖的AB包b先加载进来。
    三层依赖关系(常用):预制体prefab->材质mat->图片ui
    四层依赖关系(难做)
    注意:同一个AB包(在卸载之前)只能加载一次(不管是否在同一脚本中,只要是在一个项目中)
    //从AB包中加载预制体,把预制体实例到界面
    //加载AB包
    AssetBundle uiAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/ui");
    AssetBundle matAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/mat");
    AssetBundle prefabAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/prefab");
    //从AB包中加载预制体
    GameObject prefab = prefabAB.LoadAsset<GameObject>("Cube");
    //实例化预制体
    Instantiate(prefab, transform);

    每一个AB包都对应一个.manifest文件(资源清单),包含如下信息

    ManifestFileVersion: 0//版本号
    CRC: 1860656504//CRC循环冗余码
    Hashes://资源文件的哈希码,用于检查增量的构建AB包
      AssetFileHash:
        serializedVersion: 2
        Hash: 82edae0095f36a303261e62246d831ae
      TypeTreeHash:
        serializedVersion: 2
        Hash: 81fd706e1561f1cfc1872b1168421ee0
    HashAppended: 0
    ClassTypes://该AB包中所有资源使用到的类类型,一般情况下对应的都是地址
    - Class: 1
      Script: {instanceID: 0}
    - Class: 114
      Script: {fileID: 11500000, guid: d533bd1959b71b4459e871de8a9975af, type: 3}
    - Class: 115
      Script: {instanceID: 0}
    Assets://对应该AB包中的所有资源
    - Assets/Prefabs/Cube.prefab
    Dependencies://该AB包的直接依赖
    - "D:/Unity3Du6E38u620Fu5F00u53D1u5DE5u7A0Bu5E08u73ED1803u671F-u706Bu661Fu65F6u4EE3/Unity3D/Unity_Projects/m3w3d2_Lesson32/Assets/StreamingAssets/AssetBundle/ui"//路径里的中文用16进制显示
    单一的AssetBundle.Manifest文件:
    1、所有的AssetBundle
    2、所有的AB包的依赖(可以通过获取AssetBundle.Manifest文件,来获取AB包的依赖关系)
    注意:AssetBundle.Manifest文件的名字,会根据父文件夹的名字改变
    ManifestFileVersion: 0
    CRC: 1678997246
    AssetBundleManifest:
      AssetBundleInfos:
        Info_0:
          Name: ui
          Dependencies: {}
        Info_1:
          Name: mat
          Dependencies: {}
        Info_2:
          Name: prefab
          Dependencies:
            Dependency_0: ui
     
    不知道资源的依赖关系,自动去获取依赖项和加载依赖项
    使用AB包的步骤
    1、加载总的构建的AB包
    2、从单一的AB包中去加载构建清单
    3、从构建清单中获取指定的AB包的所有的依赖项,并加载所有的依赖项
    4、加载资源所在的AB包
    5、从AB包中加载资源
    //使用AB包的步骤
    //1、加载总的构建的AB包
    AssetBundle singleAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/AssetBundle");
    //2、从单一的AB包中去加载构建清单
    AssetBundleManifest singleManifest = singleAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
    //3、从构建清单中获取指定的AB包的所有的依赖项,并加载所有的依赖项
    //singleManifest.GetAllDependencies("prefab");获取所有的依赖,不管直接还是间接
    //singleManifest.GetDirectDependencies("prefab");获取所有的直接依赖
    string[] deps = singleManifest.GetAllDependencies("prefab");
    for (int i = 0; i < deps.Length; i++)
    {
        //Debug.Log(deps[i]);
        AssetBundle depAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/" + deps[i]);
    }
    //4、加载资源所在的AB包
    AssetBundle prefabAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/prefab");
    //5、从AB包中加载资源
    GameObject prefab = prefabAB.LoadAsset<GameObject>("Cube");
    Instantiate<GameObject>(prefab, transform);
    public string[] GetAllDependencies(string assetBundleName);//获取所有依赖(老版本没有)
    public string[] GetDirectDependencies(string assetBundleName);//获取直接依赖
    AB包的卸载
    Unload(bool)
    当传入true时,不光卸载内存中的AssetBundle对象,还卸载从这个AB包中加载到的资源。
    当传入false时,只卸载内存中的AB包,不卸载从AB中加载的资源。
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class UnloadAB : MonoBehaviour {
        public AssetBundle uiAB;
        public AssetBundle matAB;
        public AssetBundle prefabAB;
        public GameObject prefab;
        // Use this for initialization
        void Start () {
            uiAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/ui");
            matAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/mat");
            prefabAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AssetBundle/prefab");
            prefab = prefabAB.LoadAsset<GameObject>("Cube");
            Instantiate<GameObject>(prefab, transform);
        }
           
           // Update is called once per frame
           void Update () {
            if (Input.GetKeyDown(KeyCode.Space))//按空格键卸载
            {
                uiAB.Unload(false);
                matAB.Unload(false);
                prefabAB.Unload(false);
            }
        }
    }
    字典:
    简介:
    1、字典里的每一个元素都是一对键值对(由两个元素组成:一个是键一个是值)
    2、字典的键必须是唯一的,值不需要唯一
    3、键和值都可以是任意的类型(比如:基本类型,自定义类型)
    4、可以通过键去访问值
     
    字典的使用:
    1、必须引用命名空间using System.Collections.Generic;
    2、
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class LessonDictionary : MonoBehaviour {
    
    
        //动态数组的申请方式
        List<string> list = new List<string>();
        //定义一个键是string类型,值是string类型的字典
        Dictionary<string, string> dic1 = new Dictionary<string, string>();
        //定义一个键是string类型,值是GameObject类型的字典
        Dictionary<string, GameObject> dic2 = new Dictionary<string, GameObject>();
    
    
        // Use this for initialization
        void Start () {
            //对list进行添加元素
            list.Add("nihao");
            //字典的添加元素,添加的是键值对,第一个参数键,第二个参数值
            dic1.Add("a", "A");
            //这种方式也能添加元素
            dic1["b"] = "C";
    
    
            //list改变值的方式
            list[0] = "1";
            //字典改变这个键对应的值的方式
            dic1["a"] = "B";
    
    
            //list通过索引访问元素
            Debug.Log(list[0]);
            //字典通过键去访问这个键对应的值
            Debug.Log(dic1["a"]);
            Debug.Log(dic1["b"]);
    
    
            //list删除元素
            list.Remove("1");
            //字典删除元素,通过键去删除这个键值对
            dic1.Remove("a");
    
    
            //list的遍历
            for (int i = 0; i < list.Count; i++)
            {
                Debug.Log(list[i]);
            }
            foreach (var item in list)//不能改值,且效率低,产生内存碎片
            {
                Debug.Log(item);
            }
    
    
            //字典的遍历
            //遍历字典的键
            foreach (var item in dic1.Keys)
            {
                Debug.Log(item);//打印的键
                Debug.Log(dic1[item]);//打印的值
            }
            //遍历字典的值
            foreach (var item in dic1.Values)
            {
                Debug.Log(item);//打印字典的值
            }
            //遍历字典的键值对
            foreach (KeyValuePair<string,string> item in dic1)
            {
                Debug.Log(item.Key);//打印字典的键
                Debug.Log(item.Value);//打印字典的值
            }
    
    
            //list里是否有“1”这个元素
            if (list.Contains("1"))
            {
            }
            //判断字典里是否有“a”这个键
            if (dic1.ContainsKey("a"))
            {
            }
            string value = "";
            //这个方法的返回值,这个字典里有没有第一个参数的这个键
            //如果有,那么把这个键所对应的值放在out参数的value里
            if (dic1.TryGetValue("a", out value))
            {
            }
    
    
            //删除list的所有元素
            list.Clear();
            //删除字典的所有元素
            dic1.Clear();
        }
    }

    专门负责加载AB包的管理器

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class LoadManager
    {
        #region 单例
        private static LoadManager instance;
        public static LoadManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new LoadManager();
                }
                return instance;
            }
        }
        private LoadManager()
        {
            abDic = new Dictionary<string, AssetBundle>();
            abPath = Application.streamingAssetsPath + "/AssetBundle/";
            singleABName = "AssetBundle";
        }
        #endregion
        /// <summary>
        /// 用来存储已经加载的AB包,键是AB包的名字,值就是AB包。
        /// </summary>
        public Dictionary<string, AssetBundle> abDic;
        //用来存储单一的ab包
        public AssetBundle singleAB;
        //单一的构建清单,所有的ab包的依赖全部从这获取
        public AssetBundleManifest singleManifest;
        //存储ab包的路径
        public string abPath;
        //单一的ab包的名字
        public string singleABName;
        /// <summary>
        /// 加载单一的ab包,和单一的构建清单
        /// </summary>
        private void LoadSingleAssetBundle()
        {
            //每次加载单一的ab包需要判断是否加载果过。
            //singleAB为null没加载过,不为null就是加载过
            if (singleAB == null)
            {
                singleAB = AssetBundle.LoadFromFile(abPath + singleABName);
            }
            //从单一的ab包中加载单一的构建清单
            if (singleManifest == null)
            {
                singleManifest = singleAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            }
        }
        /// <summary>
        /// 加载指定ab包的所有的依赖项
        /// </summary>
        /// <param name="abName"></param>
        private void LoadAllDependencies(string abName)
        {
            LoadSingleAssetBundle();
            //首先先获取指定的这个ab包的所有的依赖项
            //从单一的构建清单中获取
            string[] deps = singleManifest.GetAllDependencies(abName);
            //遍历去加载依赖项
            for (int i = 0; i < deps.Length; i++)
            {
                //加载该依赖项前,先判断之前加载没加载过该依赖项
                //就是判断存储ab包的字典里有没有这个ab包
                if (!abDic.ContainsKey(deps[i]) )
                {
                    //如果未加载过,需要加载
                    AssetBundle ab = AssetBundle.LoadFromFile(abPath + deps[i]);
                    //ab包加载完之后,把加载来的ab包存储在字典里
                    abDic[deps[i]] = ab;
                }
            }
        }
        /// <summary>
        /// 加载指定的ab包,并且返回该ab包
        /// </summary>
        /// <param name="abName"></param>
        /// <returns></returns>
        public AssetBundle LoadAssetBundle(string abName)
        {
            LoadAllDependencies(abName);
            //加载指定的ab包
            //加载前先判断是否已经加载过,如果加载过,把加载过的ab包给你
            //如果未加载过,就加载该ab包
            //方法一:
            //if (abDic.ContainsKey(abName))//证明该ab包已经加载过
            //{
            //    return abDic[abName];
            //}
            //AssetBundle ab = ab = AssetBundle.LoadFromFile(abPath + abName);
            //abDic[abName] = ab;
            //return ab;
            //方法二:优化重构
            AssetBundle ab = null;
            if (!abDic.TryGetValue(abName, out ab))
            {
                //如果进入到这,证明该键没有指定的值,那么证明该ab包未加载,需要加载
                ab = AssetBundle.LoadFromFile(abPath + abName);
                //把加载进来的ab包添加到字典中
                abDic[abName] = ab;
            }
            return ab;
        }
        /// <summary>
        /// 加载指定的ab包中的指定名字的指定类型的资源
        /// </summary>
        /// <typeparam name="T">指定资源的类型</typeparam>
        /// <param name="abName">ab包的名字</param>
        /// <param name="assetName">资源的名字</param>
        /// <returns></returns>
        public T LoadAssetByAB<T>(string abName, string assetName) where T : Object
        {
            //先获取指定的ab包
            AssetBundle ab = LoadAssetBundle(abName);
            if (ab != null)
            {
                return ab.LoadAsset<T>(assetName);
            }
            else
            {
                Debug.LogError("指定的ab包的名字有误!");
            }
            return null;
        }
        /// <summary>
        /// 卸载指定的ab包
        /// </summary>
        /// <param name="abName"></param>
        /// <param name="unloadAllloadedObjects"></param>
        public void UnloadAssetBundle(string abName, bool unloadAllloadedObjects)
        {
            //方法一:
            //if (abDic.ContainsKey(abName))
            //{
            //    abDic[abName].Unload(unloadAllloadedObjects);
            //    abDic.Remove(abName);
            //}
            //方法二:优化重构
            //先判断有没有这个ab包
            AssetBundle ab = null;
            if (abDic.TryGetValue(abName, out ab))
            {
                //卸载ab包
                ab.Unload(unloadAllloadedObjects);
                //从容器中删除该ab包
                abDic.Remove(abName);
            }
        }
        /// <summary>
        /// 卸载全部的ab包
        /// </summary>
        /// <param name="unloadAllloadedObjects"></param>
        public void UnloadAllAssetBundle(bool unloadAllloadedObjects)
        {
            //遍历每一个ab包,调用ab包的卸载的方法
            //遍历键,通过键去获取值进行卸载
            foreach (var item in abDic.Keys)
            {
                abDic[item].Unload(unloadAllloadedObjects);
            }
            //直接遍历值去卸载
            foreach (var item in abDic.Values)
            {
                item.Unload(unloadAllloadedObjects);
            }
            abDic.Clear();
        }
    }

    测试管理器

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class TestManager : MonoBehaviour {
        public UnityEngine.UI.Image image;
           // Use this for initialization
           void Start () {
            //先加载指定ab包,再加载包中的指定名字的指定类型的资源
            //AssetBundle ab = LoadManager.Instance.LoadAssetBundle("prefab");
            //GameObject prefab = ab.LoadAsset<GameObject>("Cube");
            //直接加载指定的ab包中的指定名字的指定类型的资源
            GameObject prefab = LoadManager.Instance.LoadAssetByAB<GameObject>("prefab", "Cube");
            Instantiate(prefab, transform);
            //AssetBundle ab1 = LoadManager.Instance.LoadAssetBundle("prefab");//重复加载也不会报错
            //AssetBundle ui = LoadManager.Instance.LoadAssetBundle("ui");
            //Sprite sp = ui.LoadAsset<Sprite>("beijing_02");
            Sprite sp = LoadManager.Instance.LoadAssetByAB<Sprite>("ui", "beijing_02");
            image.sprite = sp;
        }
           
           // Update is called once per frame
           void Update () {
                  
           }
    }
    热更新的流程(判断是否进行热更新)
    1、先把最新的资源打包成AB包,把最新的AB包上传到服务器上,并且修改服务器端资源版本号。
    2、客户端一启动游戏,首先判断本地的版本号与服务器的版本号是否一致。
    3、如果不一致,从服务器下载最新的资源AB包替换本地的AB包。
    4、 解析最新的AB包从中加载想要的资源。
  • 相关阅读:
    Java代码:response压缩响应
    SpringBoot框架:第一章:基础配置和介绍
    asp.net 发送email
    .NET环境下水晶报表使用总结
    ASP.net(c#)生成条形码
    表格操作类(添加,删除,排序,上移,下移)
    NET email
    C#如何打印条形码EAN13码
    在asp.net中备份还原SQL Server数据库
    配置SQL2000数据库发送邮件
  • 原文地址:https://www.cnblogs.com/vuciao/p/10363692.html
Copyright © 2020-2023  润新知