Unity学习笔记之AB包(AssetBundle)

存储在Resources下的资源,最终会存储在游戏的主体包中,发送给用户,手机系统上,如果需要做资源的更新,是无法使用Resources即时更新(不需要关闭手机游戏,即可实现游戏更新).

AssetBundle(简称AB包):

AB包是独立于游戏主包存在的资源存储文件,使用内部资源时,需要单独下载和加载。

AB包和Resources的区别:

  • 存储:Resources内部资源存储在游戏的发布包中;
  •         AB包存储在独立的文件中(AB包存储在非特殊目录下时,不在游戏的发布包中);
  • 加载:Resources内部资源使用Resources.Load();
  •         AB包(可以理解为可下载的Resources
  •          *获得AB包文件(下载,解压streaming拷贝到可写目录
  •         加载步骤1:通过AB包文件路径,加载AB包文件
  •         加载步骤2:通过名称(资源名称),加载内部资源

AssetBundle的定义:

  •         AssetBundle是把一些资源文件,场景文件或二进制文件以某种紧密的方式保存在一起的一些文件。
  •          AssetBundle内部不能包含C#脚本文件,AssetBundle可以配合Lua实现资源和游戏逻辑代码的更新。

热更新: 不关闭Unity应用的前提,实现游戏资源和代码逻辑的更新。

AB包的创建:

        资源导入项目

                如果资源未来做更新(资源存储在AB包中),就不要将资源放置在Resources目录下;

        资源配置

                

  •                 选中需要添加AB包的资源,填写或选择已存在的AB包名称;
  •                 AB包配置修改后或AB内部的资源修改后,都需要重新生成AB包;
  •                 AB包名称如果配置为这样的结构”ui/package”,ui会作为AB包存储的父目录,package是AB包的名称;
  •                 导入到AB包的资源,包内部是不存在目录的;

        生成AB包脚本编写(编辑器脚本)。

AB包压缩方式(实际选择根据项目情况分析)

  •         不压缩:AB包比较大,下载较慢,加载速度快(CPU不用运算解压缩)
  •         LZMA算法压缩:默认压缩模式,文件尺寸居中,加载速度居中
  •         LZ4算法压缩:5.3以后可用,压缩比例高,文件小,加载速度偏慢

依赖关系:

        如果一个AB(名称A)包,使用到了另一个AB(名称B)包的资源,那么两个AB包就产生了依赖关系。也就是A依赖于B。在主 manifest 文件中,存储了依赖关系

        

导出核心代码:

        一般会写一个顶部菜单栏按钮,便于随时导出AB包;

        AB包分平台,所以导出的API不同

        导出核心代码:

//参数1:AB包文件存储路径
//参数2:导出选项
//参数3:平台(不同平台的ab包是不一样的)
BuildPipeline.BuildAssetBundles(
            path,
            BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.ForceRebuildAssetBundle,
            platform
        );

        导出选项:

  •         None:无任何选项
    •         UncompressedAssetBundle:默认压缩模式为LZMA,开启这个选项就不会压缩AB包
      •         CollectDependencies:默认开启,开启依赖记录机制
        •         DeterministicAssetBundle:将AssetBundle的哈希校验值,存储在ID中(默认开启)
          •         ForceRebuildAssetBundle:强制重新导出所有的AB包
            •         ChunkBasedCompression:使用LZ4算法压缩AB包

        导出后的目录结构:

        

        和存储目录同名的文件和文件.manifest,是主AB包及主AB包配置文件;

        无扩展名文件:AB包;文件名.manifest文件:AB包对应的配置文件。

加载AB包内部数据:

如果想处理依赖关系的加载,则必须加载主AB包,因为依赖关系的存储,都存储在主AB包的配置文件中。

  • 第一步(加载依赖的AB包文件)
  •         1、加载主AB包
  •         2、根据主AB包的配置文件,获得我当前需要加载的AB所依赖的AB们
  •         3、将所有的依赖AB们,加载进来
  • 第二步(加载AB包文件)
  •         AB包 = AssetBundle.LoadFromFile(AB包文件路径)
  •                                        .LoadFromFileSync(AB包文件路径)(异步加载)
  • 第三步(加载AB包内资源)
  •         资源对象 = AB包对象.LoadAsset<资源类型>("资源名称")
  •                                         .LoadAssetSync<资源类型>("资源名称")(异步加载)
  • 注意!AB包不能重复加载

Unity性能分析工具:

点击Window/Profiler,可以打开分析工具

Resources.Load() 加载后的资源,Unity会存储在内存中,所以即使场景中的对象被删除,资源的内存占用依然存在,只有使用Resources.UnloadUnusedAssets()释放后,没有被场景引用的资源内存才会被释放。

一些代码

多平台导出AB包:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;

public class ExportAB
{
    [MenuItem("AB包导出/Windows")]
    public static void ForWindows()
    {
        Export(BuildTarget.StandaloneWindows);
    }

    [MenuItem("AB包导出/Mac")]
    public static void ForMac()
    {
        Export(BuildTarget.StandaloneOSX);
    }

    [MenuItem("AB包导出/iOS")]
    public static void ForiOS()
    {
        Export(BuildTarget.iOS);
    }

    [MenuItem("AB包导出/Android")]
    public static void ForAndroid()
    {
        Export(BuildTarget.Android);
    }

    private static void Export(BuildTarget platform)
    {
        //项目的Assets目录的路径,比如xxxxxxx/Assets
        string path = Application.dataPath;

        //有个需求,我想把包导出到与Assets同级的ab目录下
        //比如最终路径,xxxxxxx/ab,通过对path修改实现
        path = path.Substring(0, path.Length - 6) + "ab";

        //防止路径不存在
        if(!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        //导出ab包的核心代码,生成ab包文件
        //参数1:ab包文件存储路径
        //参数2:导出选项
        //参数3:平台(不同平台的ab包是不一样的)
        BuildPipeline.BuildAssetBundles(
            path,
            BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.ForceRebuildAssetBundle,
            platform
        );

        Debug.Log("导出ab包成功");
    }
}

一般像存储路径这种固定数据我们会写一个配置类用于存放,便于多个类调用以及统一修改

public class Config
{
    //配置AB包存储的路径
    public static string ABPath = Application.dataPath.Substring(0, Application.dataPath.Length - 6) + "ab";
}

有时需要异步加载:

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

public class AsyncLoad : MonoBehaviour
{
    void Start()
    {
        //同步加载代码
        //GameObject.Find("/Canvas/Image").GetComponent<Image>().sprite = Resources.Load<Sprite>("参考图");

        //通过开启协同,执行一个异步Resources加载资源
        //StartCoroutine(LoadImage());

        //AssetBundle ab = AssetBundle.LoadFromFile(Config.ABPath + "/big");
        //GameObject.Find("/Canvas/Image").GetComponent<Image>().sprite = ab.LoadAsset<Sprite>("参考图");
        
        StartCoroutine(LoadAB());
    }

    //从Resources加载
    IEnumerator LoadImage()
    {
        //开启一个异步加载
        ResourceRequest rr = Resources.LoadAsync<Sprite>("参考图");
        //协同会在加载资源成功后,继续执行(底层封装了线程加载资源)
        yield return rr;
        //将加载成功的资源,显示出来
        GameObject.Find("/Canvas/Image").GetComponent<Image>().sprite = rr.asset as Sprite;
    }

    //从AB包加载
    IEnumerator LoadAB()
    {
        AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Config.ABPath + "/name"); // 这里为具体导出的AB包名
        yield return abcr;
        GameObject.Find("/Canvas/Image").GetComponent<Image>().sprite = abcr.assetBundle.LoadAsset<Sprite>("参考图");
    }
}

处理带有依赖关系的AB包:

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

public class Load : MonoBehaviour
{
    void Start()
    {
        //加载主AB包
        AssetBundle main = AssetBundle.LoadFromFile(Config.ABPath + "/ab");

        //获取主AB包的配置文件
        AssetBundleManifest manifest = main.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

        //分析预制体所在AB包,依赖哪些AB包
        //deps存储了所有依赖的ab包的名字
        string[] deps = manifest.GetAllDependencies("test2");   //test2为我想加载的包

        //加载依赖的AB包
        for(int i = 0; i < deps.Length; i++)
        {
            AssetBundle.LoadFromFile(Config.ABPath + "/" + deps[i]);
        }

        //加载预制体所在的AB包
        AssetBundle test2 = AssetBundle.LoadFromFile(Config.ABPath + "/test2");

        //加载预制体
        Object prefab = test2.LoadAsset("Image");

        GameObject img = Instantiate(prefab) as GameObject;
        img.transform.SetParent(GameObject.Find("/Canvas").transform);
        img.transform.localPosition = Vector3.zero;
        img.transform.localScale = Vector3.one;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_63122730/article/details/132617668
今日推荐