目录
基础介绍
Unity 中的 AssetBundles 是一种用于存储和加载各种资源的打包机制。它们允许开发者将游戏资源(如场景、模型、纹理、声音等)打包成一个或多个文件,这些文件可以在游戏运行时动态加载。AssetBundles 主要用于优化资源的管理和减少应用的初始下载大小。
核心概念
-
资源打包:AssetBundles 允许将不同的资源打包成一个集合,方便统一管理和加载。
-
按需加载:资源可以在需要时动态加载,而不是一开始就加载所有资源,这有助于减少内存使用和启动时间。
-
资源更新:使用 AssetBundles 可以在不发布新版本的情况下更新游戏内容,适用于动态内容更新和热更新。
-
跨平台:AssetBundles 可以针对不同的平台进行优化和打包,确保资源在各平台上以最优方式使用。
性能优化
- 减少包大小:合理组织和分配资源到AssetBundles中,以减少每个包的大小。
- 按需加载:只在需要时加载特定的AssetBundle,避免不必要的内存占用。
- 缓存管理:合理管理缓存的AssetBundles,以避免重复下载。
注意事项
- 依赖管理:处理好资源间的依赖关系,避免重复包含相同的资源。
- 版本控制:在更新AssetBundle时,确保版本兼容性,避免引起错误。
- 内存管理:注意AssetBundle的内存使用,特别是在移动设备上。
实践应用
- 动态内容加载:游戏可以动态加载新的关卡、角色、皮肤等,而无需重新下载整个游戏。
- 热更新和远程资源:AssetBundles 可以从远程服务器下载,实现游戏内容的热更新。
使用 AssetBundles 可以在不发布新游戏版本的情况下更新游戏内容。
动态资源加载
-
资源分离:在使用 AssetBundles 时,游戏的资源不是直接嵌入在游戏的主安装包中,而是被打包成一个或多个独立的 AssetBundle 文件。
-
远程托管:这些 AssetBundle 文件可以被托管在远程服务器上,而不是用户的设备上。
-
按需下载:游戏可以根据需要从远程服务器下载这些 AssetBundle 文件。例如,当玩家进入一个新的游戏关卡时,游戏可以下载包含该关卡资源的 AssetBundle。
更新和添加内容
-
更新资源:开发者可以更新服务器上的 AssetBundle 文件,比如修复一个纹理,添加新的声音效果,或者改进一个模型。当游戏下次请求这个 AssetBundle 时,会获取到更新后的版本。
-
添加新内容:同样,开发者可以在服务器上添加全新的 AssetBundle 文件来增加游戏内容,比如新的关卡、角色或道具。
-
动态加载:当这些更新的或新添加的 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
-
减少资源依赖:
- 首先场景直接依赖了UI资源和人物资源包。
- 采取的策略是将 UI 也划分到一个单独的包中,并为其创建一个专门的目录和 AssetBundle。
-
处理人物资源的加载:
- 为了去除场景对人物资源的直接依赖,比如提到使用胶囊体来代表人物位置,并配置生成信息。
- 通过编辑组件参数来动态生成所需内容,如角色和模型信息。
- 目的是减少场景与人物资源的直接依赖,通过动态配置和实例化来加载人物。
为了减少场景对人物的依赖,将其替换为胶囊体
分离场景和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 码来实现增量更新的基本步骤:
-
生成配置文件的 MD5 哈希值:在每次更新前,生成当前配置文件的 MD5 哈希值,并将其存储在服务器上。
-
客户端请求服务器上的配置文件 MD5 值:在游戏启动或定期检查更新时,客户端会向服务器请求最新的配置文件的 MD5 值。
-
服务器比较 MD5 值:服务器将客户端请求的 MD5 值与服务器上存储的当前配置文件的 MD5 值进行比较。
-
确定是否需要更新:如果客户端的 MD5 值与服务器上的不匹配,那么说明配置文件已经发生了变化,客户端需要下载新的配置文件。
-
客户端下载并应用新的配置文件:客户端从服务器下载新的配置文件,并用它替