Unity热更新之AssetBundle

1、加载Unity的AssetBundle

        在Window菜单栏下的PackageManager里面搜AssetBundle,如下图:

        有些版本在PackageManager里面找不到这个,可以找到项目的Package文件夹,打开manifest.json文件,添加一行信息即可,然后打开unity即可

"com.unity.assetbundlebrowser": "1.7.0",

2、 AB资源打包

        我们可以在想要打包的资源的inspect窗口最下方选择把该资源放进某个包里,也可以在这里创建新包

        在打开Window菜单栏下的AssetBundle,就会显示下面的界面,在Configure就可以看到所有创建的包,和包里面的内容。

         切换到Build界面配置打包信息

扫描二维码关注公众号,回复: 17285056 查看本文章
  • BuildTarget :选择打包的平台
  • Output Path :选择输出后的文件夹 
  • Clear Floders :选择了之后,每次都会先清空文件夹,再打包
  • Copy to StreamingAssets :会把打包后的文件复制一份到StreamingAssets文件夹,这个文件夹的位置在Asset下面
  • Compression (压缩的模式):NoCompression 不压缩、解压快、包体大,不推荐; LZMA 压缩最小,解压满,但是用一个资源会把所有资源都解压出来; LZ4  压缩比LZMA大一点,但加载资源时候,用什么解压什么,不会全部解压出来,内存占用低
  • -----------(上面这几个比较重要)---------
  • Exclude Type Information :表示在资源包中不包含资源的类型信息
  • Force Rebuild :每次打包会把所有的包都重写构建,类似于Clear Floders,但是不会删除不再存在的包
  • Ignore Type Tree Changes:增量构建检查时,忽略类型数的更改
  • Append Hash:将文件的哈希值附加到资源包名上
  • Strict Mode:严格模式,如果打包错误了,则打包直接失败,无法成功
  • Dry Run Build:运行时构建

        最后点击build就可以了!build结束后会出现这个两个文件夹

3、AB包资源加载

        创建一个测试脚本,拖拽到场景的一个空物体上来进行测试。

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

public class ABTest : MonoBehaviour
{
    public Image image;
    AssetBundle ab;
    void Start()
    {
        //加载AB包
        ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
        //加载AB包中的资源
        //只用名字加载的话会出现同名不同类型资源分不清,返回的对象是object类型
        //Object obj = ab.LoadAsset("Cube");
        //建议使用泛型加载或者是Type指定类型
        GameObject obj = ab.LoadAsset<GameObject>("Cube");
        //GameObject obj = ab.LoadAsset("Cube", typeof(GameObject)) as GameObject;
        Instantiate(obj);
  

        //AB包不能重复加载 否则报错
        //AssetBundle ab2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");  !!打咩

        //异步加载——>协程
        StartCoroutine(LoadABRes("head", "微信图片_20210926193813"));
    }

    IEnumerator LoadABRes(string ABName, string resName)
    {
        //加载AB包
        AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + ABName);
        yield return abcr;
        AssetBundleRequest abq = abcr.assetBundle.LoadAssetAsync(resName, typeof(Sprite));
        yield return abq;
        image.sprite = abq.asset as Sprite;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //卸载所有加载的AB包,参数为true的话,会把通过AB包加载的资源也卸载了;
            AssetBundle.UnloadAllAssetBundles(true);
        }
        if (Input.GetKeyDown(KeyCode.A))
        {
            //卸载指定AB包,参数为true的话,会把通过该AB包加载的资源也卸载了;
            ab.Unload(true);
        }
    }
}

        上面代码通过AB包加载了一个立方体,还有一张图片,(具体内容得看你打包了什么文件)

4、AB包的依赖

        AB包依赖:如果一个资源身上用到了其他AB包中的资源,这个时候如果只加载了自己的AB包,可能会出现资源丢失的情况,这个时候我们需要把依赖包一起加载才能正常显示。eg:包a的一个模型,用到了包b里面的一个材质,这样我们使用包a来加载这个模型的时候,材质就会丢失。但如果我们同时加载了包b的话,模型就能正常显示。 

        打包的时候我们会发现,会多一个包,这个包的名字取决于前面的Output path,这个就是主包

        解决办法AB包依赖的方法就是利用主包 获取依赖信息

//解决ab包依赖
//1、加载主包
AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "StandaloneWindows");
//2、加载主包中的固定文件
AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest("AssetBundleManifest");
//3、从固定文件中得到依赖信息
string[] strs = abManifest.GetAllDependencies(ab.name);
//4、遍历依赖包的名字,并加载
for(int i = 0; i < strs.Length; i++)
{
    AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + strs[i]);
}

5、AB包资源管理器

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

public class ABManager : Singleton<ABManager>
{


    //字典用来存储所有以及加载过的AB包
    private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();

    private AssetBundle mainAB = null;
    private AssetBundleManifest manifest = null;//配置文件
    string PathUrl { get { return Application.streamingAssetsPath + "/"; } }
    string MainABName { get => "StandaloneWindows"; }

    /// <summary>
    /// 加载AB包
    /// </summary>
    /// <param name="name"></param>
    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);
        }
    }

    //同步加载,不指定类型
    public Object LoadRes(string abName,string resName)
    {
        LoadAB(abName);
        //返回要加载的资源
        return abDic[abName].LoadAsset(resName);
    }
    //同步加载,根据type指定类型
    public Object LoadRes(string abName, string resName, System.Type type)
    {
        LoadAB(abName);

        Object obj = abDic[abName].LoadAsset(resName, type);
        //返回要加载的资源
        return obj;
    }
    //同步加载,根据泛型指定类型
    public T LoadRes<T>(string abName, string resName) where T:Object
    {
        LoadAB(abName);
        //返回要加载的资源
        return abDic[abName].LoadAsset<T>(resName);
    }


    //异步加载(资源加载使用了异步,ab包加载没有使用)
    public void LoadResAsync(string abName,string resName,UnityAction<Object> callBack)
    {
        StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
    }
    private IEnumerator ReallyLoadResAsync(string abName, string resName, UnityAction<Object> callBack)
    {
        LoadAB(abName);
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);
        yield return abr;
        callBack(abr.asset);
    }

    //异步加载,根据type
    public void LoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
    {
        StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
    }
    private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
    {
        LoadAB(abName);
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName,type);
        yield return abr;
        callBack(abr.asset);
    }

    //异步加载 泛型
    public void LoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T:Object
    {
        StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callBack));
    }
    private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T : Object
    {
        LoadAB(abName);
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
        yield return abr;
        callBack(abr.asset as T);
    }

    //单个包卸载
    public void UnLoadABPackage(string abName)
    {
        if (abDic.ContainsKey(abName))
        {
            abDic[abName].Unload(false);
            abDic.Remove(abName);
        }
        else { Debug.Log("不存在该AB包:" + abName); }
    }
    //所有包卸载
    public void UnloadAllABPackage()
    {
        AssetBundle.UnloadAllAssetBundles(false);
        abDic.Clear();
        mainAB = null;
        manifest = null;
    }
}

猜你喜欢

转载自blog.csdn.net/buzhengli/article/details/134362575