Noções básicas do AssetBundle

Conceito de bolsa AB

O que é um pacote AB: Semelhante a um pacote compactado, exceto pelo código C#, outros itens u3d comuns podem basicamente ser empacotados.
Comparado com resource.load, a vantagem é que os recursos são um bloco grande e não podem ser modificados. Os pacotes AB podem ser compactado de qualquer forma e colocado em outro local.
Função: realizar atualizações quentes de recursos/código, atualizar por meio de comparação de recursos
e reduzir o tamanho do corpo do pacote inicial. Você pode baixar o pacote AB posteriormente.

Geração de pacote AB

Ferramentas de empacotamento personalizadas podem ser desenvolvidas e implementadas com base no editor u3d. O oficial também fornece um conjunto de fluxos de trabalho. Baixe o AssetBundleBrowser e você pode associar recursos ao método de compactação do corpo do pacote: 1. A compactação LZMA é a menor, a descompactação é lenta e
requer toda descompactação 2. LZ4 usa um recurso para descompactar uma parte, e a taxa de compactação não é tão alta, e a descompactação é rápida. O
pacote principal compactado armazena informações de dependência chave e a configuração de armazenamento de manifesto
https://github.com/ Unity-Technologies/AssetBundles-Browser

Leitura de pacote AB

Pasta especial do Unity: streamingasset. Ao compactar, copie o pacote AB para streamingasset, que pode ser empacotado junto com o projeto. Ao mesmo tempo, existe uma API para ler diretamente o pacote ab do streamingasset.

API da unidade:

Carregamento síncrono

AssetBundle.LoadFromFile(path)//加载ab包
ab.LoadAsset<T>(name)//加载ab包中对应的物体
ab.LoadAsset("Cube",typeof(T)) as T//不用泛型的方式,兼容Lua
Instaniate

Carregamento assíncrono

IEnumerator LoadABRes(abName,resName)
{
	var abcr = AssetBundle.LoadFromFileAsync(path);
	yield return abcr;
	var abq = ab.LoadAssetAsync("Cube",typeof(T)) ;
	yield return abq;
	abq.asset as T
}

Como o thread único U3D implementa a corrotina

O princípio da corrotina Unity utiliza principalmente o recurso iterador do C#. Um iterador é uma função que retorna os elementos de uma sequência, usando a instrução yield return para retornar cada elemento e reter o estado da função. Por exemplo:

// 一个简单的迭代器函数
IEnumerator CountToTen {
for (int i = 1; i <= 10; i++) {
Console.WriteLine(i); // 输出 1 到 10
yield return null; // 暂停一帧
}
}

Quando chamamos uma função iteradora, ela retorna um objeto da interface IEnumerator.Este objeto possui duas propriedades: Current e MoveNext. Current representa o elemento retornado atualmente e MoveNext representa se existe um próximo elemento. Cada vez que MoveNext é chamado, a função iteradora continua a execução de onde foi pausada pela última vez até que a próxima instrução de retorno de rendimento seja encontrada ou a função termine.

A corrotina do Unity é implementada com base neste mecanismo. Quando usamos o método StartCoroutine para iniciar uma corrotina, o Unity adicionará a corrotina a uma lista e verificará todas as corrotinas nesta lista entre Update e LateUpdate de cada quadro, chamará seu método MoveNext e determinará se deve pausar ou continuar a corrotina com base sobre o valor do retorno do rendimento.

Dependências do pacote AB

Se houver ativos no pacote que dependem de outros pacotes, você precisará carregar o pacote dependente antes de carregar o pacote.
O método é usar o pacote principal para obter informações de dependência.
Primeiro carregue o pacote principal e depois retire a configuração arquivo LoadAsset do pacote principal.
Você pode usar GetAllDependencies do pacote principal (Nome do pacote), obter todos os nomes de pacotes dependentes do pacote de destino e, em seguida, encontrar todos os pacotes dependentes. A desvantagem
é que sabemos o relacionamento entre os pacotes, não a relação entre ativos e pacotes, por isso devemos fazer com que bons recursos sejam gerenciados

Gerenciador de carregamento de recursos de pacote AB

BV1LD4y1m7kF

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

/// <summary>
/// 知识点 1.单例模式 2.委托 3.协程 4.字典
/// </summary>
public class ABManager : SingletnoAutoMono<ABManager>
{
    //AB包管理器 目的是 让外部更方便的进行资源加载
    //主包
    private AssetBundle mainAB = null;

    //依赖包获取用的配置文件
    private AssetBundleManifest mainfest = null;

    //AB包不能重复加载 重读加载会报错
    //用字典来存储 加载过的AB包

    private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();

    /// <summary>
    /// 存放AB包路径 方便修改
    /// </summary>
    private string PathUrl
    {
        get
        {
            return Application.streamingAssetsPath + "/";
        }
    }

    private string MainABName
    {
        get
        {
#if UNITY_IOS
            return "IOS"
#elif UNITY_ANDROID
            return "Android"
#else
            return "PC";
#endif
        }
    }/// <summary>

     /// 加载AB包 </summary> <param name="abname"></param>
    private void LoadAB(string abName)
    { //加载AB包
        if (mainAB == null)
        {
            mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
            mainfest = mainAB.LoadAsset<AssetBundleManifest>(nameof(AssetBundleManifest));
        }
        //获取包的依赖信息
        AssetBundle ab = null;
        string[] strs = mainfest.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);
        }
    }

    /// <summary>
    /// 同步加载,不指定类型
    /// </summary>
    /// <param name="abName"></param>
    /// <param name="resName"></param>
    /// <returns></returns>
    public object LoadRes(string abName, string resName)
    {//加载AB包
        LoadAB(abName);
        //在加载资源时,判断资源是不是Gameobjtct
        //如果是 直接实例化 再返还给外部
        Object obj = abDic[abName].LoadAsset(resName);
        if (obj is GameObject)
        {
            return Instantiate(obj);
        }
        else
        {
            return obj;
        }

        //加载资源
        //return abDic[abName].LoadAsset(resName);
    }

    /// <summary>
    /// 同步加载,根据type 指定类型 lua不支持泛型,因此写重载方法
    /// </summary>
    /// <param name="abName"></param>
    /// <param name="resName"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    public object LoadRes(string abName, string resName, System.Type type)
    {
        LoadAB(abName);
        //在加载资源时,判断资源是不是Gameobjtct
        //如果是 直接实例化 再返还给外部
        Object obj = abDic[abName].LoadAsset(resName, type);
        if (obj is GameObject)
        {
            return Instantiate(obj);
        }
        else
        {
            return obj;
        }
    }

    /// <summary>
    /// 同步加载 根据泛型指定类型
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="abName"></param>
    /// <param name="resName"></param>
    /// <returns></returns>
    public T LoadRes<T>(string abName, string resName) where T : Object
    {
        LoadAB(abName);
        //在加载资源时,判断资源是不是Gameobjtct
        //如果是 直接实例化 再返还给外部
        T obj = abDic[abName].LoadAsset<T>(resName);
        if (obj is GameObject)
        {
            return Instantiate(obj);
        }
        else
        {
            return obj;
        }
    }

    //异步加载
    //AB包没有使用异步加载
    //只是从AB包加载资源时,使用异步
    /// <summary>
    /// 根据名字异步加载
    /// </summary>
    /// <param name="abName"></param>
    /// <param name="resName"></param>
    /// <param name="callback">使用delegate或者lamada表达式直接对传出的参数object进行操作</param>
    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)
    {//加载AB包
        LoadAB(abName);
        //在加载资源时,判断资源是不是Gameobjtct
        //如果是 直接实例化 再返还给外部
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);

        yield return abr;
        //异步加载结束后 通过委托,传递给外部,外部来使用。 
        if (abr.asset is GameObject)
        {
            callback(Instantiate(abr.asset));
        }
        else
        {
            callback(abr.asset);//将参数传出去
        }
    }

    /// <summary>
    /// 根据Type 异步加载资源
    /// </summary>
    /// <param name="abName"></param>
    /// <param name="resName"></param>
    /// <param name="type"></param>
    /// <param name="callback"></param>
    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)
    {//加载AB包
        LoadAB(abName);
        //在加载资源时,判断资源是不是Gameobjtct
        //如果是 直接实例化 再返还给外部
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName, type);

        yield return abr;
        //异步加载结束后 通过委托,传递给外部,外部来使用。
        if (abr.asset is GameObject)
        {
            callback(Instantiate(abr.asset));
        }
        else
        {
            callback(abr.asset);//将参数传出去
        }
    }

    /// <summary>
    /// 根据泛型 异步加载资源
    /// </summary>
    /// <param name="abName"></param>
    /// <param name="resName"></param>
    /// <param name="callback"></param>
    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
    {//加载AB包
        LoadAB(abName);
        //在加载资源时,判断资源是不是Gameobjtct
        //如果是 直接实例化 再返还给外部
        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);//将参数传出去
        }
    }

    //单个包卸载
    public void UnLoad(string abName)
    {
        if (abDic.ContainsKey(abName))
        {
            abDic[abName].Unload(false);
            abDic.Remove(abName);
        }
    }

    //所有包的卸载
    public void ClearAB()
    {
        AssetBundle.UnloadAllAssetBundles(false);
        abDic.Clear();
        mainAB = null;
        mainfest = null;
    }
}

Guess you like

Origin blog.csdn.net/TongOuO/article/details/132125186