AssetBundle的学习

1.AssetBundle简称AB包,是一种特定平台的压缩资产文件,类似于压缩包。

  • AB包的资产包括模型,贴图,预设体,材质球,音效等。(不包括C#代码,所以使用lua进行热更新)

2.AB的作用

  • 相对于Resource文件下的资源AB能更好的管理资源
    Resource文件与AB的区别:Resource在打包时是只读文件,无法进行修改,AB包的存储方式可以自定义,压缩状态可以自定义,后期可以动态更新。

  • 减少包体大小
    可以压缩资源,减少初始包的大小,易于传播

  • 可以热更新
    1.资源的热更新
    2.脚本的热更新

  • 热更新的基本规则
    客户端:自带一些默认资源和一个资源对比管理文件。
    服务器端:资源服务器地址,资源对比文件,各种AB包。
    第一步,客户端会从服务器中获得资源服务器地址。
    第二部,在资源服务器的资源对比文件,检查需要更新或者下载的AB包,下载AB包完成热更新。

3.生成AB包资源文件

  • 使用官方提供的Asset Bundle Browser
  • Build
    • 在打包Build中先要选择额打包平台然后是打包路径。

    • 压缩方式有三种
      1.不压缩
      2.Standard Compression(LMZZ),这种方式压缩最彻底,压缩出来的AB文件最小,不够要使用其中的一个资源时,需要解压所有文件。
      3.Chunk Based Compression(LZ4),压缩后的AB包大小略微大于LMZZ方式的压缩,但是用什么解压什么不用解压所有资源建议使用。

    • ETI:在资源包中 不包含资源的类型信息。

    • FR:重新打包时需要重新构建包,和Clear Folders不同,不会删除不再存在的包。

    • ITTC:增量构建检查时,忽略类型数的更改。

    • Append Hash:将文件哈希值附加到资源包名上。

    • SM:严格模式,如果打包时报错了,则打包直接失败无法成功。

  • Inspect
    • 观察包里的信息,资源,大小等。
    • 在打包的路径中查看打包后的文件有三种文件,.meta,.manifest,和AB包
      1.AB包文件无后缀,是资源文件。
      2.manifest文件:AB包文件信息,AB包依赖关系,版本信息。
      3.主包也是AB包(名字和目录名一致),有所有包的依赖关系(非常重要)

4.使用AB包资源文件
1.同步加载AB包

public class ABTest : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        //第一步 加载AB包
        AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
        //第二步 加载AB包中的资源(三种方式)
        GameObject obj = ab.LoadAssert("Cube");  //仅使用名字加载,会出现同名不同类型资源分不清的情况,不建议使用
        GameObject obj = ab.LoadAssert<GameObject>("Cube"); //使用泛型加载
        GameObject obj = ab.LoadAssert("Cube",typeof(GameObject) as GameObject); //Type指定泛型(lua不支持泛型)
        Instantiate(obj);  //实例化
    }
}

2.异步加载AB包

public class ABTest : MonoBehaviour
{
  void Start()
  {
      //异步加载 --> 协程
      StartCoroutine(LoadABRes("head","myhead")); //此时myhead是图片资源
  }

  IEnumerator LoadABRes(string ABName, string resName)
  {   
      //第一步 加载资源包
      AssetBundleCreateRequest abcr = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + ABName);
      yield return abcr;
      //加载资源
      AssetBundleCreateRequest abq = abcr.assetBundle.LoadAssertAsync(resName,typeof(Sprite)); //若已知是图片资源
      yield return abq;
      img.Sprite = abq.asset as Sprite;
  }
}

3.卸载AB包资源

//参数为true时会把通过AB包加载的资源也卸载掉
abq.Unload(false); //卸载单个AB包
AssetBundle.UnloadAllAssetBundle(false);//卸载所有加载的AB包 

5.AB包的依赖

  • 假设有A,B,C,D这4个AB包,A中的a1中的资源用到了B,C中的资源那么必须加载A,B,C这三个包,否则a1将无法正常加载。往往一个资源会依赖多个AB包,这时就可以用主包中的依赖关系解决。
  • 主包中记录的依赖关系是包与包之间的依赖关系,不会记录资源与包的依赖关系,比如a2依赖D中的资源,要加载a2还是会加载A,B,C,D这4个包。所以资源依赖了哪几个包无法知道。
//加载主包
AssetBundle abMain = AssetBundle(Application.streamingAssetsPath + "/" + "PC"); //这里PC为主包名
//加载主包中的固定文件 
AssetBundle abManifest = AssetBundle.LoadAssert<AssetBundleManifest>("AssetBundleMainfest");
//从固定文件中 得到依赖信息
string[] strs = abManifest.GetAllDependencies("model"); //不用填路径
//得到了依赖包的名字
for(int i = 0; i < strs.Length; i++)
{
     AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + strs[i]);
}

6.AB包资源加载管理器

  • 同步加载
    • 加载依赖包先要加载主包,加载主包得到其中的配置文件,通过配置文件得到相关的依赖包,然后加载依赖包,用键值对的方式来判断是否加载过次AB包。
    • 加载依赖包。
    • 从目标包中加载资源。
public class ABMgr : SingletonAutoMono<ABMgr>
{
    //声明主包
    private AssetBunle mainAB = null;
    //声明依赖包获取用的配置文件
    private AssetBundleMainfest manifest = null;

    //字典 用来存储加载过的AB包 (重复加载会报错)
    private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
    //AB包存放路径,方便修改
    private string PathUrl
    {
        get
        {
            return Application.streamingAssetsPath + "/"; //测试用的路径
            // Application.persistentDataPath + "/" + "PC"; //热更路径
        }
    }

    //主包名 方方便修改
    private string MainABName
    {
        get
        {
            #if UNITY_IOS
                return "IOS";
            #elif UNITY_ANDROID
                return "Android";
            #else
                return "PC";
            #endif
        }
    }

    //加载AB包
    public void LoadAB(string abName)
    {
        if(mainAB == null)
        {
            mainAB = AssetBundle.LoadFromFile(PathUrl, MainABName);
            manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        }
        //获取依赖包相关信息
        AssetBundle ab = null;
        string[] strs = manifest.GetAllDependencies(abName);
        for (int i = 0; i < strs.Length; i++)
        {
            //判断包是否加载过
            if(!abDic.ContainsKey(strs[i]))
            {
                ab = AssetBundle.LoadFromFile(PathUrl + strs[i])
                abDic.Add(strs[i], ab);
            }
        }
        //加载资源来源包 
        if(!abDic.ContainsKey(abName))
        {
        ab = AssetBundle.LoadFromFile(PathUrl + abName);
        abDic.Add(abName, ab);
        }
    }

    //同步加载1  不指定类型
    public Object LoadRes(string abName, string resName)
    {
        //加载AB包
        LoadAB(abName);
        //加载资源
        Object obj = abDic[abName].LoadAsset(resName);
        if (obj is GameObject)
            return Instantiate(obj);
        else 
            return obj;
    }

    //同步加载2 根据type指定类型 lua常用
    public object LoadRes(string abName, string resName, System.Type type)
    {
        //加载AB包
        LoadAB(abName);
        //指定类型加载  避免不同类型文件名相同时在一个包里面分不清类型的情况
        Object obj = abDic[abName].LoadAsset(resName, type);
        if (obj is GameObject)
            return Instantiate(obj);
        else 
            return obj;
    }

    //同步加载3 根据泛型指定类型加载
    public T LoadRes<T>(string abName, string resName) where T:Object
    {
        //加载AB包
        LoadAB(abName);
        //指定类型加载  避免不同类型文件名相同时在一个包里面分不清类型的情况
        T obj = abDic[abName].LoadAsset<T>(resName);
        if (obj is GameObject)
            return Instantiate(obj);
        else 
            return obj;
    }
}
  • AB包卸载时
//单个包卸载
public void Unload(string abName)
{
    if(abDic.ContainsKey(abName))
    {
        abDic[abName].Unload(false);
        abDic.Remove(abName);
    }
}

//所有包卸载
public void ClearAB()
{
     AssetBundle.UnloadAssetBundle(false);
     abDic.Clear();
     mainAB = null;
     mainfest = null;
}
  • 异步加载
    这里的异步加载指从AB包中加载资源时使用异步方法,加载AB包未使用异步加载方式
    1.根据名字异步加载
public void LoadAssetAsyn(string abName, string resName, UnityAction<Object> callBack)
{
    StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
}
private IEnumerable ReallyLoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
    //加载AB包
    LoadAB(abName);
    //加载资源
    AssetBundleRequest abr = abDic[abName].LoadAssetAsyn(resName);
    yield return abr;
    //异步加载结束后,通过委托 传递给外部 外部来使用
    if (abr.asset is GameObject)
        callBack(Instantiate(abr.asset));
    else 
        callBack(abr.asset);
}

2.根据type异步加载

public void LoadAssetAsyn(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
    StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
}
private IEnumerable ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
    //加载AB包
    LoadAB(abName);
    //加载资源
    AssetBundleRequest abr = abDic[abName].LoadAssetAsyn(resName, type);
    yield return abr;
    //异步加载结束后,通过委托 传递给外部 外部来使用
    if (abr.asset is GameObject)
        callBack(Instantiate(abr.asset));
    else 
        callBack(abr.asset);
}

3.根据泛型异步加载

public void LoadAssetAsyn<T>(string abName, string resName, UnityAction<T> callBack) where T:Object
{
    StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callBack));
}
private IEnumerable ReallyLoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T:Object
{
    //加载AB包
    LoadAB(abName);
    //加载资源
    AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
    yield return abr;
    //异步加载结束后,通过委托 传递给外部 外部来使用
    if (abr.asset is GameObject)
        callBack(Instantiate(abr.asset) as T);
    else 
        callBack(abr.asset) as T;
}
posted @   kano_ne  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示