Bootstrap

Unity AssetBundle学习笔记

目录

基础介绍

动态资源加载

更新和添加内容

打包策略

资源分组

频繁更新的资源

资源压缩

Unload(true)和Unload(false)

Unload(false)

Unload(true)

确定何时卸载

引用计数

场景和状态管理

资源使用频率

内存预算和监控

用户输入和游戏逻辑

处理依赖关系

 依赖管理

使用 AssetBundle Manifest

减少资源依赖的资源管理实战案例

内存占用查看

版本更新处理


基础介绍

Unity 中的 AssetBundles 是一种用于存储和加载各种资源的打包机制。它们允许开发者将游戏资源(如场景、模型、纹理、声音等)打包成一个或多个文件,这些文件可以在游戏运行时动态加载。AssetBundles 主要用于优化资源的管理和减少应用的初始下载大小。

核心概念

  1. 资源打包:AssetBundles 允许将不同的资源打包成一个集合,方便统一管理和加载。

  2. 按需加载:资源可以在需要时动态加载,而不是一开始就加载所有资源,这有助于减少内存使用和启动时间。

  3. 资源更新:使用 AssetBundles 可以在不发布新版本的情况下更新游戏内容,适用于动态内容更新和热更新。

  4. 跨平台:AssetBundles 可以针对不同的平台进行优化和打包,确保资源在各平台上以最优方式使用。

性能优化

  • 减少包大小:合理组织和分配资源到AssetBundles中,以减少每个包的大小。
  • 按需加载:只在需要时加载特定的AssetBundle,避免不必要的内存占用。
  • 缓存管理:合理管理缓存的AssetBundles,以避免重复下载。

注意事项

  • 依赖管理:处理好资源间的依赖关系,避免重复包含相同的资源。
  • 版本控制:在更新AssetBundle时,确保版本兼容性,避免引起错误。
  • 内存管理:注意AssetBundle的内存使用,特别是在移动设备上。

实践应用

  • 动态内容加载:游戏可以动态加载新的关卡、角色、皮肤等,而无需重新下载整个游戏。
  • 热更新和远程资源:AssetBundles 可以从远程服务器下载,实现游戏内容的热更新。

使用 AssetBundles 可以在不发布新游戏版本的情况下更新游戏内容。

动态资源加载

  1. 资源分离:在使用 AssetBundles 时,游戏的资源不是直接嵌入在游戏的主安装包中,而是被打包成一个或多个独立的 AssetBundle 文件。

  2. 远程托管:这些 AssetBundle 文件可以被托管在远程服务器上,而不是用户的设备上。

  3. 按需下载:游戏可以根据需要从远程服务器下载这些 AssetBundle 文件。例如,当玩家进入一个新的游戏关卡时,游戏可以下载包含该关卡资源的 AssetBundle。

更新和添加内容

  1. 更新资源:开发者可以更新服务器上的 AssetBundle 文件,比如修复一个纹理,添加新的声音效果,或者改进一个模型。当游戏下次请求这个 AssetBundle 时,会获取到更新后的版本。

  2. 添加新内容:同样,开发者可以在服务器上添加全新的 AssetBundle 文件来增加游戏内容,比如新的关卡、角色或道具。

  3. 动态加载:当这些更新的或新添加的 AssetBundles 被下载到用户设备上后,游戏可以动态加载这些资源,实现内容的更新或添加。

优势

  • 减少下载大小:初始游戏安装包可以更小,因为不需要包含所有资源。
  • 减少更新频率:减少需要通过应用商店发布的完整游戏更新的频率。
  • 灵活性:允许更加灵活地管理游戏内容和推出新内容。

实际应用

  • 热更新:常用于游戏的热更新,允许快速修复错误或调整游戏平衡。
  • 活动和季节性内容:方便地为游戏添加特殊活动或季节性内容。

打包策略

资源分组

  • 按类别分组:将相似类型的资源分组打包,如将所有纹理放在一个 AssetBundle,所有模型放在另一个。
  • 按用途分组:根据资源在游戏中的使用情景进行分组。例如,一个游戏关卡的所有资源可以打包在一个 AssetBundle 中。

频繁更新的资源

  • 单独打包:将可能会经常更新的资源单独打包,以便在不影响其他内容的情况下更新它们。

资源压缩

  • 选择合适的压缩格式:根据资源类型和平台需求选择合适的压缩格式,以减少 AssetBundle 的大小。

Unload(true)和Unload(false)

Unload(false)

当调用 Unload(false) 时,Unity 会卸载 AssetBundle 对象本身,但不会卸载通过该 AssetBundle 加载进来的任何对象(如纹理、模型、预制件等)。这意味着:

  • 内存保留:已加载的资源(例如通过 AssetBundle 加载的游戏对象和纹理)会保留在内存中。
  • AssetBundle 对象卸载:AssetBundle 的引用被清除,意味着不能再从这个 AssetBundle 加载新的资源。

这种卸载方式适用于那些需要保留已加载资源的场景,例如,如果你已经使用 AssetBundle 中的资源创建了游戏对象,并且希望这些对象在卸载 AssetBundle 后仍然可用。

Unload(true)

调用 Unload(true) 时,Unity 不仅卸载 AssetBundle 对象,还会卸载所有通过该 AssetBundle 加载并实例化的资源。这包括:

  • 内存释放:通过该 AssetBundle 加载的所有资源都将从内存中卸载。
  • 资源不再可用:之前从这个 AssetBundle 加载的所有对象将不再可用,并且如果这些对象还在场景中,它们可能会停止工作或显示为丢失状态。

这种卸载方式适用于需要完全清理资源的情况,例如,当玩家离开某个游戏关卡并且不再需要该关卡资源时。

确定何时卸载

怎么确定什么时候AB包的资源不用了,什么时候进行卸载,使用什么算法

引用计数

引用计数是一种常见方法,用于跟踪资源被多少个对象或系统所引用:

  • 增加引用:当一个对象开始使用某个资源时,该资源的引用计数增加。
  • 减少引用:当对象不再使用该资源时,引用计数减少。
  • 判断卸载:当资源的引用计数降到零时,可以安全地卸载该资源。

场景和状态管理

基于游戏的当前状态或场景来管理资源:

  • 按场景卸载:在场景切换时卸载特定场景相关的资源。
  • 状态机:使用状态机来管理游戏状态,根据不同状态加载和卸载资源。

资源使用频率

分析资源的使用频率和最近使用时间:

  • LRU(Least Recently Used)算法:定期检查资源的最近使用时间,如果某个资源在一定时间内未被使用,则将其标记为可卸载。
  • 使用频率:跟踪资源使用的频率,低频使用的资源可以被优先考虑卸载。

内存预算和监控

设定内存预算并监控实际使用情况:

  • 内存限制:为资源设定内存预算。当接近或超过预算时,开始卸载最不常用的资源。
  • 性能监控:实时监控应用的内存使用情况,当内存使用达到某个阈值时触发资源清理。

用户输入和游戏逻辑

根据用户行为或游戏逻辑来决定资源的加载和卸载:

  • 用户操作:用户进入或退出某个游戏模块时,加载或卸载相关资源。
  • 游戏进度:根据游戏进度和玩家成就来动态管理资源。

处理依赖关系

 依赖管理

  • 处理依赖关系:Unity 允许自动处理 AssetBundle 间的依赖关系。如果一个 AssetBundle 依赖于另一个,则加载时必须先加载它所依赖的那个。
  • 避免重复包含:确保不会有重复资源在多个 AssetBundle 中出现,以减少冗余。

使用 AssetBundle Manifest

  • 生成和使用 Manifest:当你在 Unity 中构建 AssetBundles 时,Unity 会自动生成一个名为 "Manifest" 的文件,其中包含了所有 AssetBundles 及其依赖关系的信息。
  • 读取依赖:在加载任何 AssetBundle 之前,首先加载其 Manifest 文件,并使用它来了解该 AssetBundle 所有的依赖。
  • 按顺序加载依赖:根据 Manifest 提供的信息,先加载所有依赖的 AssetBundles,然后加载目标 AssetBundle。

如果两个包中含有重复的资源,可以将这部分重复的资源单独打成一个包:

点击Move duplicate to new bundle

此时两个原来的包就会依赖于这个新包了

不过依赖关系一般不建议超过三层

将所有角色打包在一个大包里好还是每个角色单独分包好呢?

后者好,因为一方面更新单个角色时可以只更新那一部分,

而且加载小的资源包所花的时间也更短

如果是多个角色打在一个包里,那在加密和解密的时候,需要把其他角色相关的资源也进行解密才能加载出该包,这样也费时间。

unity中 一个AB包只能被加载一次,为了适应这种规则,必须记录哪些包是被加载过的

例如改成下面这样:

减少资源依赖的资源管理实战案例

当游戏中的场景资源依赖于UI和人物资源时,如何管理?

教学源自:06实战!分离依赖和加载(人物,UI)包_哔哩哔哩_bilibili

  1. 减少资源依赖

    • 首先场景直接依赖了UI资源和人物资源包。
    • 采取的策略是将 UI 也划分到一个单独的包中,并为其创建一个专门的目录和 AssetBundle。
  2. 处理人物资源的加载

    • 为了去除场景对人物资源的直接依赖,比如提到使用胶囊体来代表人物位置,并配置生成信息。
    • 通过编辑组件参数来动态生成所需内容,如角色和模型信息。
    • 目的是减少场景与人物资源的直接依赖,通过动态配置和实例化来加载人物。

为了减少场景对人物的依赖,将其替换为胶囊体

分离场景和UI的依赖

  • 删除场景中的UI元素,创建专门的加载对象(Canvas loader)来管理UI加载。
  • 目的是进一步解耦场景和UI的直接依赖关系。

重构资源加载接口

原有的UI资源是存放在Resources下并调用相关的api进行加载的,现在将其打包在AB包里,因此需要对相应的接口做一些重构:

  • 将UI使用的资源从 Resources 文件夹移出,并重新部署这些资源。
  • 修改原有基于 Resources 的资源加载接口,改为从新的加载框架加载。
  • 目的是从 Resources 文件夹中完全解脱出来,改进资源加载机制。

图中内容就是将UI相关的资源往外移

内存占用查看

首先创建场景时勾选下面两个选项

在运行后,按下ctrl+7可以打开profiler

当使用了LoadFile的时候,就会将文件加载出来放在内存中

此时就可以在工具里查看内存的使用情况

simple模式下可以看各类资源的使用情况

detailed模式下可以看到AB包下的每个资源分别占用了多少的内存:

版本更新处理

首先比较服务器上最新的版本号,判断版本号是否一致

如果不一致则进行更新。

在比较文件时往往是只比较配置文件的md5值而不是比较一个一个文件的md5值,原因如下

比较配置文件的 MD5 码是一种实现增量更新的有效方法之一。这是因为配置文件通常相对较小,而且更容易比较和更新。

下面是一种使用配置文件的 MD5 码来实现增量更新的基本步骤:

  1. 生成配置文件的 MD5 哈希值:在每次更新前,生成当前配置文件的 MD5 哈希值,并将其存储在服务器上。

  2. 客户端请求服务器上的配置文件 MD5 值:在游戏启动或定期检查更新时,客户端会向服务器请求最新的配置文件的 MD5 值。

  3. 服务器比较 MD5 值:服务器将客户端请求的 MD5 值与服务器上存储的当前配置文件的 MD5 值进行比较。

  4. 确定是否需要更新:如果客户端的 MD5 值与服务器上的不匹配,那么说明配置文件已经发生了变化,客户端需要下载新的配置文件。

  5. 客户端下载并应用新的配置文件:客户端从服务器下载新的配置文件,并用它替

;