Unity 热更新技术 | (二) AssetBundle - 完整系列教程学习
迪丽瓦拉
2025-05-30 05:04:09
0

请添加图片描述

  • 🎬 博客主页:https://xiaoy.blog.csdn.net

  • 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉

  • 🎄 学习专栏推荐:Unity系统学习专栏

  • 🌲 游戏制作专栏推荐:游戏制作

  • 🌲Unity实战100例专栏推荐:Unity 实战100例 教程

  • 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

  • 📆 未来很长,值得我们全力奔赴更美好的生活✨

  • ------------------❤️分割线❤️-------------------------

请添加图片描述

Unity 热更新技术最新系列全面教程

  • Unity 热更新技术 | (二) AssetBundle - 完整系列教程学习
      • 前言
    • 一、什么是AssetBundle
    • 二、AssetBundle作用
    • 三、AssetBundle三种压缩格式
    • 四、AB打包流程
    • 五、AB包具体使用方式
        • 5.1 官方提供的打包工具:AssetBundle Browser
        • 5.2 将对象保存为预制体并为预制体设置AB包信息
        • 5.3 执行打包方法
        • 5.4 加载AB包,并使用其中的资源文件
        • 5.5 AB包的加载流程
    • 六、AssetBundle依赖关系
    • 七、AssetBundle分组策略
    • 总结

在这里插入图片描述

Unity 热更新技术 | (二) AssetBundle - 完整系列教程学习

请添加图片描述


前言

  • 开始学习热更新方面系列知识,就从这一篇开始吧!
  • 本系列教程 会从热更新基本概念出发,详细介绍热更新相关的全套知识点。
  • 如热更新技术基本原理、热更新主流方案、AssetBundle系列教程、Lua语言编程、Lua与Unity交互教程、Xlua框架使用、热更新实战教程等方面。
  • 热更新作为一个开发者必备技能,如果想学习的话,可以从现在开始了哦~
  • 接下来从 AssetBundle - 完整系列教程学习 开始学习吧!

一、什么是AssetBundle

  AssetBundle(简称AB包)是一个资源压缩包,可以包含模型、贴图、音频、预制体等。如在网络游戏中需要在运行时加载资源,而AssetBundle可以将资源构建成 AssetBundle 文件。

在这里插入图片描述


二、AssetBundle作用

1、AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至整个场景,可以在游戏运行的时候被加载;
2、AssetBundle自身保存着互相的依赖关系;
3、压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网络传输;
4、把一些可以下载内容放在AssetBundle里面,可以减少安装包的大小;


三、AssetBundle三种压缩格式

AssetBundle 提供了三种压缩格式:

  1. 不压缩(BuildAssetBundleOptions.UncompressedAssetBundle):优点是需要加载资源时速度非常快,缺点是构建的 AssetBundle 资源文件会比较大。
  2. LZMA压缩(BuildAssetBundleOptions.None):unity中默认的压缩方式,优点是会将文件压缩的非常小,缺点是每次使用都需要将压缩的文件全部解压,非常耗费时间,可能会造成游戏的卡顿,不推荐在项目中使用。
  3. LZ4压缩(BuildAssetBundleOptions.ChunkBasedCompression):是LZMA和不压缩之间的折中方案,构建的 AssetBundle 资源文件会略大于 LZMA 压缩,但是在加载资源时不需要将所有的资源都加载下来,所以速度会比 LZMA 快。建议项目中使用它。

四、AB打包流程

  1. 设置资源AssetBundle名称
  2. BuildPipeline,BuildAssetBundles打包
  3. 处理打包后的文件
  4. Ab包依赖描述

在这里插入图片描述


五、AB包具体使用方式

5.1 官方提供的打包工具:AssetBundle Browser

下载官方提供的打包工具,两种下载方式:

  1. git地址:https://github.com/Unity-Technologies/AssetBundles-Browser
  2. 在资源管理器中打开Packages的manifest.json文件,在"dependencies": {}中添加一行代码:“com.unity.assetbundlebrowser”: “1.7.0”,

下载之后导入Unity工程即可,如遇报错可以删掉Test文件夹即可。

打开方式:Windows -> AssetBundle Browser 启动打包除窗口。
在这里插入图片描述

5.2 将对象保存为预制体并为预制体设置AB包信息

在场景中新建几个游戏对象做测试,将其拖到Resources下当做预制体。

在这里插入图片描述

然后在监视器面板中设置AB包的信息,选中该物体,在右下角设置AB包名称。

在这里插入图片描述

这样就可以在面板中看到我们设置的AB包信息了。设置的时候会根据AB包不同名称分别打到不同的包中。

在这里插入图片描述

5.3 执行打包方法

选择对应的平台及输出路径,然后根据情况选择其他配置。

在这里插入图片描述

参数含义如下

  • Build Target:打包平台选择
  • Output Path :文件输出路径
  • Clear Folders:清空路径内容
  • Copy to StreamingAssets:将打包后的内容复制到Assets/StreamingAssets文件夹下
  • Advanced Settings
    • Exclude Type Infomation:在资源包中 不包含资源的类型信息
    • Force Rebuild:重新打包时需要重新构建包
      和ClearFolder不同,他不会删除不再存在的包
    • Ignore Type Tree Changes:增量构建检查时,忽略类型数的修改
    • Apped Hash:将文件哈希值附加到资源包名上
    • Strict Mode:严格模式,如果打包报错了,则打包直接失败无法成功
    • Dry Run Build:运行时构建

点击Build后会执行打包方法,等待打包完成即可获得对应的AB包文件。

若是上面选择了 Copy to StreamingAssets,则会打包出来两份资源。
一个与Asset同级目录,另一个则是在Assets/StreamingAssets文件夹下。

在这里插入图片描述

其中有一个主包文件和对应的AB包资源文件。

内容大致为以下几个部分:

  • AB包文件:资源文件
  • manifest文件:AB包文件信息(资源信息,依赖关系,版本信息等等)
  • 关键AB包(与打包目录名相同的包):主包文件,包含AB包依赖的关键信息

在这里插入图片描述
在这里插入图片描述

5.4 加载AB包,并使用其中的资源文件

上面已经讲到了打包AB包的方法,下面就是学习怎样加载我们打包好的AB包,并使用其中的资源。

在这里插入图片描述

下面直接使用LoadFromFile()方法进行AB包的加载及使用,代码如下:

1.使用同步加载方法 LoadFromFile()

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class ABLoadDemo : MonoBehaviour
{public Button LoadAb_Btn;private string LoadPath;//AB包路径private void Awake(){LoadPath = Application.streamingAssetsPath;LoadAb_Btn.onClick.AddListener(LoadAB);}/// /// 同步加载/// private void LoadAB(){//第一步:加载AB包AssetBundle ab = AssetBundle.LoadFromFile(LoadPath + "/"+"module");//第二步:加载AB包中的资源//GameObject abGO = ab.LoadAsset("bullet");//方法一:使用LoadAsset<>泛型加载//GameObject abGO = ab.LoadAsset("bullet") as GameObject;//方法二:使用LoadAsset名字加载(不推荐,会出现同名不同类型的对象无法区分的问题)GameObject abGO = ab.LoadAsset("bullet", typeof(GameObject)) as GameObject;//方法三:使用LoadAsset(Type)指定类型加载Instantiate(abGO);}
}

2.使用异步加载方法 LoadFromFileAsync(),使用协程辅助异步加载。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class ABLoadDemo : MonoBehaviour
{public Button LoadAbAsync_Btn;public Image image;//场景测试图片private string LoadPath;//AB包路径private void Awake(){LoadPath = Application.streamingAssetsPath;LoadAbAsync_Btn.onClick.AddListener(()=> {//启动协程完成异步加载StartCoroutine(LoadABAsync()); });}/// /// 异步加载/// /// IEnumerator LoadABAsync(){//第一步:加载AB包AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(LoadPath + "/" + "test");yield return abcr;//第二步:加载AB包中的资源AssetBundleRequest abr = abcr.assetBundle.LoadAssetAsync("head",typeof(Sprite));yield return abr;image.sprite = abr.asset as Sprite;Debug.Log("加载AB包赋值图片完成");}
}

同步加载实例化一个球体异步加载一张图片赋值给Image组件 的示例如下:

在这里插入图片描述

这样我们就学会最基本的Ab包加载和使用其中资源的方法了。

其中有个点需要注意:

  • 同一AB包不能重复加载多次,否则会报错(卸载后可重新加载)
    在这里插入图片描述

AB包卸载方式如下:

AssetBundle ab = AssetBundle.LoadFromFile(LoadPath + "/"+"module");//卸载所有AB包资源。若参数为true表示将所有使用该AB包中的资源全部卸载,反之则不会
AssetBundle.UnloadAllAssetBundles(false);//卸载某个指定AB包的方法。若参数为true表示将会把使用该AB包的场景资源也全部卸载,反之则不会
ab.Unload(false);

下面是几种常用的AB包加载方式,简单记录一下:

  1. 异步加载:AssetBundle.LoadFromMemoryAsync
    从内存区域异步创建 AssetBundle。
 /// /// 从本地异步加载AssetBundle资源,Path是AB包路径+AB包名称/// /// 路径/// IEnumerator LoadFromMemoryAsync(string path){AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));yield return createRequest;AssetBundle bundle = createRequest.assetBundle;var prefab = bundle.LoadAsset("bullet");Instantiate(prefab);}
  1. 同步加载,将等待 AssetBundle 对象创建完毕才返回。
    AssetBundle.LoadFromMemory
    AssetBundle.LoadFromMemory由AssetBundle.LoadFromMemoryAsync变化而来,与 LoadFromMemoryAsync 相比,该版本是同步的,将等待 AssetBundle 对象创建完毕才返回。
AssetBundle bundle = AssetBundle.LoadFromMemory(File.ReadAllBytes(ABPath));var prefab = bundle.LoadAsset("bullet");Instantiate(prefab);
  1. 同步加载AssetBundle.LoadFromFile
    从磁盘上的文件同步加载 AssetBundle。
    该函数支持任意压缩类型的捆绑包。 如果是 lzma 压缩,则将数据解压缩到内存。可以从磁盘直接读取未压缩和使用块压缩的捆绑包。

与 LoadFromFileAsync 相比,该版本是同步的,将等待 AssetBundle 对象创建完毕才返回。
这是加载 AssetBundle 的最快方法。

/// 
/// 从磁盘上的文件同步加载 AssetBundle。
/// 
void LoadFromFile()
{AssetBundle ab = AssetBundle.LoadFromFile(Application.dataPath + "/StreamingAssets/"+ assetBundle);var go = ab.LoadAsset("ZAY");Instantiate(go);
}
  1. 异步加载:AssetBundle.LoadFromFileAsync
    LoadFromFileAsync AssetBundle 的异步创建请求。加载后使用 assetBundle 属性获取 AssetBundle。
    从磁盘上的文件异步加载 AssetBundle。

该函数支持任意压缩类型的捆绑包。 如果是 lzma 压缩,则将数据解压缩到内存。可以从磁盘直接读取未压缩和使用块压缩的捆绑包。

IEnumerator LoadFromFileASync(string path){AssetBundleCreateRequest createRequest = AssetBundle.LoadFromFileAsync(path);yield return createRequest;AssetBundle bundle = createRequest.assetBundle;if (bundle == null){Debug.Log("Failed to load AssetBundle!");yield break;}var parefab = bundle.LoadAsset("bullet");Instantiate(parefab);}
  1. UnityWebRequestAssetBundle 和 DownloadHandlerAssetBundle
    UnityWebRequestAssetBundle 此方法将 DownloadHandlerAssetBundle 附加到 UnityWebRequest。

DownloadHandlerAssetBundle.GetContent(UnityWebRequest) 作为参数。GetContent 方法将返回你的 AssetBundle 对象。

   IEnumerator WEB(string url){UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url, 3, 0);//此方法将返回 WebRequestAsyncOperation 对象。在协程内部生成 WebRequestAsyncOperation 将导致协程暂停,//直到 UnityWebRequest 遇到系统错误或结束通信为止。yield return request.SendWebRequest();//如果加载失败if (request.result != UnityWebRequest.Result.Success){Debug.Log(request.error);yield break;}//返回下载的 AssetBundle 或 null。AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);var parefab = bundle.LoadAsset("ZAY");Instantiate(parefab);}

5.5 AB包的加载流程

再简单介绍下AB的加载流程,如下所示:

在这里插入图片描述


六、AssetBundle依赖关系

  上面讲了一下基本的 AssetBundle打包 和 加载 的方法。
在加载流程中也提到了依赖关系,下面就来讲一下AssetBundle的依赖关系,所谓依赖关系就是指某个AB包中的某个资源可能是依赖于另外一个AB包的。

比如我们打包的时候,一个AB包中的内容全是模型,而另外一个AB包中的资源都是材质,此时模型AB包中就可能需要使用到材质AB包中的资源,此时两个AB包就存在依赖关系。

下面用一个例子看一下具体效果:
首先新建一个Material材质球,改为黄色并将其赋给Player对象。

在这里插入图片描述

Player对象是勾选了AB包的,我们现在重新使用Build打包看一下AB包情况。

在这里插入图片描述

可以看到这个材质也被自动打包进了AB包中,而且Budle名是默认设置的auto。
在包中的一个资源如果使用了另外一个资源,那么打包的时候会把另外一个资源也默认打包进该包中。
此时我们可以手动修改该材质的AB包名称,然后重新打包一下。

在这里插入图片描述

此时我们再去加载AB包module获取Player对象试一下效果:

		//加载AB包AssetBundle ab = AssetBundle.LoadFromFile(LoadPath + "/"+"module");//加载AB包中的资源GameObject abGO = ab.LoadAsset("player", typeof(GameObject)) as GameObject;//实例化对象Instantiate(abGO);

可以看到游戏对象被加载出来了,但是材质发生了丢失。
在这里插入图片描述

  原因就是因为该AB包module中的Player对象使用到了materials包中的材质球资源,但是我们没有加载materials包。所以出现了材质丢失。
这就是说module包中有资源对象依赖对materials包中的资源,所以他们存在AB包依赖关系。

出现这种有依赖关系的情况时,如果只加载自己的AB包,那么通过它创建的对象就会出现资源丢失的情况(比如上方的材质丢失等),此时就需要将依赖包一起进行加载,才能保证材质不丢失。

比如上方加载module包的代码多加一行,如下所示:

		//加载AB包AssetBundle ab = AssetBundle.LoadFromFile(LoadPath + "/"+"module");//加载依赖包AssetBundle abMaterials = AssetBundle.LoadFromFile(LoadPath + "/" + "materials");//加载AB包中的资源GameObject abGO = ab.LoadAsset("player", typeof(GameObject)) as GameObject;//实例化对象Instantiate(abGO);

此时运行项目就会发现,一切正常了,模型和材质都是正常显示了。
在这里插入图片描述

但问题是如果此时我们打包了很多的AB包,并且各个AB包中的依赖关系比较复杂时,我们就没办法上面那样根据依赖包的名称手动加载了。

此时我们就可以打开AB包中的主包的manifest文件查看具体的依赖关系:
在这里插入图片描述
可以看到manifest中有标志说 资源包info_0(module包) 对 Info_1(materials包)有依赖关系。

所以说我们在代码中就可以使用主包的manifest文件来对每个AB包的依赖包进行加载。
所以代码可以更改为如下所示:

        //加载AB包AssetBundle ab = AssetBundle.LoadFromFile(LoadPath + "/"+"module");//加载主包AssetBundle abMain = AssetBundle.LoadFromFile(LoadPath + "/" + "StandaloneWindows");//加载主包中的固定文件AssetBundleManifest abManifest = abMain.LoadAsset("AssetBundleManifest");//从固定文件中得到依赖信息string[] strs = abManifest.GetAllDependencies("module");//得到依赖包的名字并加载foreach (var s in strs){Debug.Log("依赖包:"+s);AssetBundle.LoadFromFile(LoadPath + "/" + s);}//加载AB包中的资源 实例化对象 卸载所有AB包资源GameObject abGO = ab.LoadAsset("player", typeof(GameObject)) as GameObject;Instantiate(abGO);AssetBundle.UnloadAllAssetBundles(false);

在这里插入图片描述

此处注意点:在manifest文件中只能看到某个AB包依赖于哪些其他AB包,并不能看到某个AB包中资源依赖于哪个AB包中的具体资源。


七、AssetBundle分组策略

上面提到了AssetBundle的依赖关系,那么就不得不提一下AssetBundle的分组策略啦。

我们现在已经知道不同的AB包之间可能会存在各种依赖关系,那么此时对AB包的分组就显得尤为重要了。
不然的话等到项目资源越来越多、各个AB间的依赖关系越来越复杂时,足够让开发者们搞的头皮发麻。

分组策略可根据自己的项目规划进行划分,一般有下面几种分组参考:

  1. 逻辑实体分组
    a,一个UI界面或者所有UI界面一个包(这个界面里面的贴图和布局信息一个包)
    b,一个角色或者所有角色一个包(这个角色里面的模型和动画一个包)
    c,所有的场景所共享的部分一个包(包括贴图和模型)
  2. 按照类型分组
    所有声音资源打成一个包,所有shader打成一个包,所有模型打成一个包,所有材质打成一个包
  3. 按照使用类型分组
    把在某一时间内使用的所有资源打成一个包。可以按照关卡分,一个关卡所需要的所有资源包括角色、贴图、声音等打成一个包。也可以按照场景分,一个场景所需要的资源一个包
  4. 按更新频率分组
    不经常更新的放在一个包,经常更新的放在一个包分别管理。
    在这里插入图片描述

总结

  • 本文讲解了Unity中的AssetsBundle(AB 包)相关内容知识点。
  • 包括AB包概念、压缩格式、Ab包使用方式等几个方面
  • 其中Ab包使用方式这块建议仔细看一下,后续热更新方面打包的时候用到这个地方会多一点。
  • 本篇文章介绍了 AssetBundle的相关内容,后续完整的热更新方案及教程请看专栏其他文章。

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...