AB包相关知识

Lua与AB包/Addressables以及YooAsset

摘自千问:

  1. Lua菜谱(逻辑):决定了菜怎么做,味道如何。因为你需要随时换菜谱(热更新),所以菜谱不能死板地印在墙上(编译进主包)。
  2. AssetBundle外卖盒(格式):你把写好的菜谱(Lua 文件)装进外卖盒里,方便运输。
  3. Addressables / YooAsset配送系统(管理)
    • 它们负责去仓库(服务器)拿外卖盒。
    • 检查盒子是不是最新的(版本管理)。
    • 把盒子送到厨房(内存),并拆开盒子把菜谱拿出来交给厨师(Lua 虚拟机)。

值得注意的是,现在除了 Lua,还有一种流行的热更方案是 HybridCLR(原 ilruntime/huohuo 的替代者)。

  • 如果你用 HybridCLR,你的逻辑是 C# 写的,那么 Lua 的地位就会下降,可能只用来写简单的 UI 脚本或配置文件。

AB包相关概念

热更新基本规则:

AB包浏览器插件的安装

AB包浏览器文件的安装https://blog.csdn.net/qq_36303853/article/details/148812182#t5

资源概念

C#代码不能放到AB包,因为C#是编译型语言,我们才需要脚本语言lua

Unity 编辑器通过反射,实现了对预设体上组件的动态识别、属性展示------这就是为什么Csharp脚本文件不能进AB包而组件能进AB包的原因

预制体相关概念https://blog.csdn.net/2303_80204192/article/details/157287772#t1

AB包打包流程

1.给资源划分包

如果模型上有其他主包中的资源,在打包时会构建依赖关系

2.打包页面

打包后对应文件夹就会出现

build页签中的相关属性

AB包资源加载

都是先加载AB包,再加载AB包中资源

1.AB包的同步加载:

复制代码
 void Start()
    {
        //加载AB包
        AssetBundle ab=AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/model");
        //加载资源 一种泛型,一种非泛型
        GameObject go=ab.LoadAsset<GameObject>("Sphere");
        GameObject go2 =ab.LoadAsset("Sphere", typeof(GameObject)) as GameObject;

        //实例化
        Instantiate(go);
    }

注意:AB包不能重复加载,否则会报错!

2.AB包的异步加载(利用协程)

复制代码
void Start()
    {
        // 开始协程,加载 UI 精灵
        StartCoroutine(ABResLoad("head", "ui_DL_an_queding_01"));
    }

IEnumerator ABResLoad(string ABname, string resName)
    {
        // 加载 AB 包
        AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + ABname);
        yield return abcr;

        // 加载资源(Sprite)
        AssetBundleRequest abr = abcr.assetBundle.LoadAssetAsync<Sprite>(resName);
        yield return abr;

        img.sprite = abr.asset as Sprite;
    }

3.卸载AB包及其资源

cs 复制代码
void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // 卸载所有加载的 AB 包,参数为 true 会把通过 AB 包加载的资源也卸载
            AssetBundle.UnloadAllAssetBundles(false);

            //卸载单个资源
            AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/model");
            // 加载资源(泛型和非泛型两种写法)
            GameObject go = ab.LoadAsset<GameObject>("Sphere");
            // 卸载单个 AB 包
            ab.Unload(false);
        }
    }

True:AB包以及资源一起卸载 ;False:AB包卸载,资源不会卸载

AB包的依赖

如果一个模型在A包中,其材质在B包中,那么只加载A包中的模型资源会丢失材质

方法一

同时加载AB包获取模型材质和模型

方法二

这里利用主包的依赖性

cs 复制代码
//依赖包的关键知识点---利用主包 获取依赖信息
//加载主包
AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "PC");
//加载主包中的固定文件
AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//从固定文件中 得到依赖信息
string[] strs = abManifest.GetAllDependencies("model");
//得到了 依赖包的名字
for (int i = 0; i < strs.Length; i++)
{
    Debug.Log(strs[i]);
}

ManiFest文件中的依赖关系如下:

缺陷:

主包依赖关系文件只能记录包与包之间的依赖关系,至于包中资源具体依赖关系是不知道的

比如A包中a资源依赖B包C包,A包中b资源需要D包E包,使用如上代码会导致加载a资源时,也会加载不需要的D包E包

GetAllDependencies

获取Manifest文件中的与对应包中的依赖关系

我这里设定一个红色球,球的模型放在model包中,材质放在materia包中

添加然后根据AB包打包流程打包情况如下

调用API

cs 复制代码
string[] strs = mainABManifest.GetAllDependencies(abName);

abName为model(即找到model包中的依赖关系并传递给strs函数),strs参数中的数据为mateia。

AB包资源加载管理器

首先需要注意:同步加载要有三种方法:泛型方法同步加载与普通参数同步加载

额外需要注意:(Lua中不支持泛型方法,所以可能会用Type形式)

同步加载

优化端:

反正三种方法都要完成如下操作:

加载对应包------查找对应包中的依赖关系------加载对应依赖包------记录加载过的包

不如将这套流程打包成一个函数在三个方法中调用

cs 复制代码
 public void LoadAB(string abName)
    {
        //加载主包及主包的依赖关系
        if(mainAB==null)
        {
            mainAB = AssetBundle.LoadFromFile(pathUrl + MainABName);
            mainABManifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        }

        //获取依赖关系
        string[] strs = mainABManifest.GetAllDependencies(abName);
        for(int i=0;i<strs.Length;i++)
        {
            //如果AB包的依赖包没有加载过,则加载并且记录
            if(!abDic.ContainsKey(strs[i]))
            {
                AssetBundle ab = AssetBundle.LoadFromFile(pathUrl + strs[i]);
                abDic.Add(strs[i],ab);
            }
        }

        //加载资源来源包
        //如果AB包没有加载过,则加载并且记录
        if(!abDic.ContainsKey(abName))
        {
            AssetBundle ab = AssetBundle.LoadFromFile(pathUrl + abName);
            abDic.Add(abName,ab);
        }
    }

不指定类型的同步加载

cs 复制代码
public object LoadRes(string abName,string assetName)
    {
        //加载资源
        LoadAB(abName);
        //此处设计优化了一下:在加载的同时判断是否为object类型,如果是object类型则直接实例化后返回
        Object obj = abDic[abName].LoadAsset(assetName);
        if(obj is GameObject)
        {
            return Instantiate(obj);
        }
        else
        {
            return obj;
        }
    }

指定类型的同步加载

cs 复制代码
public object LoadRes(string abName,string assetName,System.Type type)
    {
        //加载资源
        LoadAB(abName);
        //此处设计优化了一下:在加载的同时判断是否为object类型,如果是object类型则直接实例化后返回
        Object obj = abDic[abName].LoadAsset(assetName,type);
        if(obj is GameObject)
        {
            return Instantiate(obj);
        }
        else
        {
            return obj;
        }
    }

外部调用该函数举例:

这里的model包中的Sphere存储是红色的球,所以会加载一个红色的球

cs 复制代码
public class ABTest : MonoBehaviour
{

    void Start()
    {
        GameObject go = ABMgr.Instance.LoadRes("model", "Sphere",typeof(GameObject)) as GameObject;
        go.transform.position = Vector3.up;
 
    }
}

泛型的同步加载

cs 复制代码
public T LoadRes<T>(string abName,string assetName) where T:Object
    {
        //加载资源
        LoadAB(abName);
        //此处设计优化了一下:在加载的同时判断是否为object类型,如果是object类型则直接实例化后返回
        T obj = abDic[abName].LoadAsset<T>(assetName);
        if(obj is GameObject)
        {
            return Instantiate(obj) as T;
        }
        else
        {
            return obj as T;
        }
    }

异步加载

这里需要注意:AB包的加载不适用异步加载,只有加载资源时才使用异步加载

与同步加载相似,也有三种加载方法

加载AB包以及AB包依赖关系与同步加载共用APi:LoadAB(abName)

不指定类型的异步加载

cs 复制代码
public void LoadResAsync(string abName,string assetName,UnityAction<Object> callback)
    {
        StartCoroutine(LoadResAsyncCoroutine(abName,assetName,callback));
    }
    

    private IEnumerator LoadResAsyncCoroutine(string abName,string assetName,UnityAction<Object> callback)
    {
        //加载AB包
        LoadAB(abName);
        //异步加载资源
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync(assetName);
        yield return abr;
        //此处设计优化了一下:在加载的同时判断是否为object类型,如果是object类型则直接实例化后返回
        Object obj = abr.asset;
        if(obj is GameObject)
        {
            callback(Instantiate(obj));
        }
    }

对传参UnityAction<T>不太了解,具体原理请看:

UnityAction https://blog.csdn.net/2303_80204192/article/details/157148540#t3

调用对应方法:

指定类型异步加载

cs 复制代码
public void LoadResAsync(string abName,string assetName,System.Type type,UnityAction<Object> callback)
    {
        StartCoroutine(LoadResAsyncCoroutine(abName,assetName,type,callback));
    }

    public IEnumerator LoadResAsyncCoroutine(string abName,string assetName,System.Type type,UnityAction<Object> callback)
    {
        //加载AB包
        LoadAB(abName);
        //异步加载资源
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync(assetName,type);
        yield return abr;
        //此处设计优化了一下:在加载的同时判断是否为object类型,如果是object类型则直接实例化后返回
        Object obj = abr.asset;
        if(obj is GameObject)
        {
            callback(Instantiate(obj));
        }
    }

根据泛型加载资源

cs 复制代码
public void LoadResAsync<T>(string abName,string assetName,UnityAction<Object> callback) where T:Object
    {
        StartCoroutine(LoadResAsyncCoroutine<T>(abName,assetName,callback));
    }

    public IEnumerator LoadResAsyncCoroutine<T>(string abName,string assetName,UnityAction<Object> callback) where T:Object
    {
        //加载AB包
        LoadAB(abName);
        //异步加载资源
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(assetName);
        yield return abr;
        //此处设计优化了一下:在加载的同时判断是否为object类型,如果是object类型则直接实例化后返回
        Object obj = abr.asset;
        if(obj is GameObject)
        {
            callback(Instantiate(obj));
        }
    }
相关推荐
lly20240611 小时前
WebPages 发布
开发语言
冉卓电子12 小时前
MPC5604B/C MC_RGM 复位模块全解
c语言·开发语言·单片机·嵌入式硬件
Chris _data12 小时前
C# 与 PLC Modbus RTU 通信实践:从单例到线程安全的连接监控
开发语言·安全·c#
不负岁月无痕12 小时前
STL-- C++ vector类 模拟实现
开发语言·c++
晚烛12 小时前
CANN 分布式通信与 HCCL:多 NPU 协作的底层机制
开发语言·人工智能·分布式·python·深度学习
装不满的克莱因瓶12 小时前
新版AI开发框架SpringAIAlibaba vs AgentScope 选型指南
java·开发语言·人工智能·ai·agent·alibaba·springai
雾酩12 小时前
深拷贝与浅拷贝:一篇彻底讲明白的入门博客
开发语言·前端·javascript
丘山望岳12 小时前
C++模板特化:类型与常量的灵活掌控
c语言·开发语言·c++
阿里嘎多学长12 小时前
2026-05-24 GitHub 热点项目精选
开发语言·程序员·github·代码托管