WAYNETS.ORG

Game and Program

AssetBundle框架

作者:

发表于

Context Polling System Post-Processing Renderer

Bundle

ABundle 是抽象基类,Bundle 是其实现类,它们基于 Unity 自带的 AssetBundle 类实现了资源的加载与管理逻辑。

类名职责
ABundle抽象定义一个 AssetBundle 的生命周期管理器,包括加载、卸载、资源获取、引用计数、依赖等逻辑。
Bundle具体实现 ABundle,利用 UnityEngine.AssetBundle 执行加载/卸载等操作。
AssetBundle(Unity 原生)实际负责读取 AssetBundle 文件、从中加载资源(例如 Prefab、Texture、AudioClip 等)。

+-------------------+
|   ABundle (抽象类)|
|-------------------|
| + Load()          | <- 定义加载接口
| + UnLoad()        | <- 定义卸载接口
| + LoadAsset()     | <- 同步加载资源
| + LoadAssetAsync()| <- 异步加载资源
| + 引用计数管理      |
| + 依赖关系预设字段  |
+-------------------+
          ↑
          | 继承
+-------------------+
|   Bundle(实现类)|
|-------------------|
| 使用 Unity 的      |
| AssetBundle 加载   |
| 本地资源文件       |
| 具体实现四个抽象方法 |
+-------------------+

          ↓
 +--------------------------+
 | UnityEngine.AssetBundle |
 +--------------------------+

BundleAsync

BundleAsync是在 ABundle 框架上扩展出的异步资源加载模块,通过 AssetBundleCreateRequest 实现非阻塞加载,并配合 Update() 轮询机制、依赖控制、引用计数等功能,构建了一个高性能、可控的异步加载系统,适用于运行时大量资源动态加载场景。

与类Bundle的函数Load()不同的是,当你调用类BunldeAsync的函数Load()时,并不会立刻返回 AssetBundle 实例,而是返回一个异步请求对象m_AssetBundleCreateRequest。由于异步加载的完成时机是不确定的,所以需要函数Update()来不断轮询异步请求对象的值isDone来判断是否加载完成,完成时,提取出它的assetBundle实例。

异步请求对象AssetBundleCreateRequest

AssetBundleCreateRequest 是 Unity 提供的一个类,继承自 AsyncOperation,用于表示正在进行中的 AssetBundle 加载操作。它是异步加载的结果句柄,我们通过isDone来判断是否加载完成,并且从assetBundle中获得成果。可以用函数Update()輪询它的状态,或者用协程等待完成。

它的设计目标是 避免阻塞主线程

当你使用异步加载方法:

AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);

Unity 不会立即返回 AssetBundle,而是返回一个 AssetBundleCreateRequest。你可以等待它完成:

yield return request; // 在协程中等待完成

AssetBundle bundle = request.assetBundle;

主要成员:

成员类型说明
assetBundleAssetBundle获取加载完成后的 AssetBundle 实例。如果请求尚未完成,返回 null
isDonebool继承自 AsyncOperation,表示是否加载完成。
progressfloat加载进度,范围 [0, 1]
allowSceneActivationbool控制是否允许激活场景(主要用于场景异步加载)。

对比:

特性Bundle(同步)BundleAsync(异步)
加载方式LoadFromFileLoadFromFileAsync
主线程阻塞否(非阻塞)
状态检查自动完成需手动调用 Update()
卸载方式显式调用 UnLoad()Update() 时若无人引用则自动卸载
使用场景小资源、本地测试、初始化大资源、场景资源、运行时热加载

同步加载 vs 异步加载

  1. 同步加载(Synchronous Loading)

定义:函数调用会阻塞主线程,直到加载完成,程序才会继续往下执行。

特点:

  • 简单易用;
  • 会造成 卡顿或掉帧,特别是加载大文件或大量资源时;
  • 不适合在游戏运行时动态加载,尤其是移动端。
AssetBundle bundle = AssetBundle.LoadFromFile("path/to/assetbundle");

2. 异步加载(Asynchronous Loading)

    定义:函数调用立即返回一个 AsyncOperation 或类似结构,加载在后台进行,加载完成后触发回调或状态变更。

    特点:

    • 不会阻塞主线程,适合运行时加载;
    • 更复杂,需要监听完成状态;
    • 更适合商业级或优化性能的项目。
    AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync("path/to/assetbundle");
    yield return request;
    AssetBundle bundle = request.assetBundle;

    使用场景推荐加载方式理由
    启动加载主UI同步 (LoadFromFile)避免复杂异步逻辑,UI资源体积小
    战斗场景中加载敌人资源异步 (LoadFromFileAsync)避免卡顿
    地图过渡加载下一区域异步玩家尚未进入时加载,体验更流畅
    编辑器下打包验证同步调试简单,能及时看到错误

    同步加载快但会卡顿;异步加载慢但流畅。大文件/运行时加载用异步,小文件/初始化用同步。

    Asset和AssetBundle的区别

    名称含义举例
    Asset资源。是最终被使用的对象一个 .prefab.png 图片、.mp3 音乐、.mat 材质球等
    AssetBundle资源包,是一组打包好的 Assets,通常从磁盘或网络加载进来Characters.abLevel01.abUICommon.ab

    AssetBundle(资源包)
     ├── Player.prefab      → Asset
     ├── Gun.png            → Asset
     └── Explosion.wav      → Asset

    BunldeManager

    BundleManager是单例模式,它是面向AssetBundle加载与管理的核心管理类,主要负责:

    • 资源路径映射
    • 加载AssetBundle
    • 自动卸载无用资源
    • 管理依赖关系
    • 管理异步加载生命周期
    • 延迟卸载逻辑

    BundleManager是一个高效、通用、可扩展的AssetBundle异步加载框架,通过缓存、泛型、安全封装和自动管理,简化了Unity热更新资源的访问与维护流程,是商业项目中资源系统的重要组成部分。

    核心类和方法:

    类/方法说明
    BundleManager管理所有加载的 AssetBundle,缓存它们,并提供加载、卸载与资源获取接口。
    LoadAsset<T>(string url)泛型接口,传入资源路径 url,异步加载并返回 T 类型资源。
    LoadAssetAsync(string url)协程方法,真正执行异步加载 AssetBundle 及资源的逻辑。
    Unload(string url)手动卸载某个已加载的资源。
    AssetRequest封装一个资源的加载状态与引用,支持自动从 AssetBundle 中加载、卸载资源。
    AssetRequest.GetAsset<T>()获取某个已加载资源的实例,带类型安全检查和自动替换逻辑。

    资源加载流程图:

    外部调用:LoadAsset<Sprite>("characters/hero")
    
    ↓
    查找缓存:
    - 如果已缓存,直接返回
    
    ↓
    如果未加载过:
    - 启动协程:LoadAssetAsync("characters/hero")
    
        ↓
        使用 WWW 或 UnityWebRequest 异步加载 .bundle 文件
        ↓
        加载完成后:bundle.LoadAsset("characters/hero", typeof(Sprite))
        ↓
        创建 AssetRequest 并缓存到字典中
    
    ↓
    调用 AssetRequest.GetAsset<T>() 返回资源引用

    Resource

    Resource

    Resource是同步加载的资源类,通过加载指定 AssetBundle 并从中同步提取出资源对象,提供访问和实例化,并支持回调与引用管理。

    在整个框架的架构中,Resource对应的是某一个具体的资源对象(如一个 Prefab、一张贴图、一段音效等)——而不是打包的 AssetBundle 本身。

    ResourceManager

    [游戏启动]
         ↓
    [ResourceManager.Initialize()]
         ↓
    [BundleManager.Initialize()]
         ↓
    [加载 manifestAssetBundle]
         ↓
    [解析 AssetBundleManifest]
         ↓
    [加载目标资源A]
         ↓
    [先找资源A所在的Bundle]
         ↓
    [根据Manifest查依赖,先加载依赖Bundles]
         ↓
    [加载资源A所在Bundle]
         ↓
    [从中加载出 Resource A(Prefab、Texture等)]

    Build打包过程

    (1)类BuildItem

    用于配置某一类资源如何打成AssetBundle的参数模型,在整个打包流程中非常关键。

    BuildItem打包配置表中的一行规则项,它告诉打包工具:

    • 要打哪个路径;
    • 如何过滤(按后缀);
    • 如何打包(按文件、目录、合并);
    • 是否参与依赖;
    • 忽略哪些路径。

    ⚠️ 它本身不会做任何打包行为,只是数据模型,供打包器(如 BuildProcessor)使用。

    (2)类BuildSetting

    BuildSetting是整个打包系统的规则总控器,负责:资源筛选、规则匹配、Bundle 命名和路径处理,是打包系统的大脑。

    BuildSetting和BuildItem的关系

    BuildSetting是统一配置和组织者,BuildItem是每个包的具体打包计划,它们一起构成了定制化的打包系统

    BuildSetting(打包总管)
    │
    ├── BuildItem A(打包 Login.prefab)
    ├── BuildItem B(打包所有声音)
    └── BuildItem C(打包所有怪物贴图)
    ↓
    Builder 执行打包
    ↓
    构建 AssetBundleBuild[]
    ↓
    调用 Unity 官方打包 API
    ↓
    输出 AB 文件和 manifest 文件

    额外问题

    (1)什么是manifestAssetBundle?

    Unity 在打包 AssetBundle 时,会额外生成一个特殊的 AssetBundle,它的名字和你指定的输出目录名一致(比如你打包到目录叫 AssetBundles,就会生成一个同名的 bundle),它就是所谓的:

    manifestAssetBundle —— 里面包含了一个 AssetBundleManifest 对象

    这个对象里记录了:

    • 所有 AssetBundle 的名字
    • 每个 AssetBundle 的直接依赖关系(哪些 Bundle 是它依赖的)
    • 是否有循环依赖
    • Bundle 的 Hash 值(用于版本控制)
    • Bundle 是否是压缩过的(chunked/compressed)

    你可以把它理解为:

    📜 AssetBundle 的“总目录”/“依赖清单”

    Read Next:


    Leave a comment