了解一下Unity的AssetBundle加载

Unity的AssetBundle系统是管理游戏资源的核心机制之一,它允许开发者将资源(如场景、预制体、纹理、音频等)打包成单独的文件,并在运行时动态加载。这种方式不仅优化了内存使用,还支持热更新,提升了游戏的灵活性和可维护性。


AssetBundle 是什么?

AssetBundle 是Unity提供的一种资源打包和加载系统。它将多个资源打包成一个或一组文件(称为AssetBundle文件),这些文件可以在运行时通过代码动态加载,而无需将所有资源直接嵌入游戏包中。

核心概念

  • 资源打包:将多个资源(如纹理、模型、音频等)组合成一个AssetBundle文件。
  • 动态加载:在游戏运行时按需加载这些文件,而不是一次性加载所有资源。
  • 独立性:AssetBundle文件可以独立于主游戏包存在,适合分发和更新。

主要优点

  • 按需加载:只加载当前需要的资源,减少初始加载时间和内存占用。
  • 热更新:支持在不重新发布游戏的情况下更新内容。
  • 资源复用:可以在不同场景或项目中复用相同的AssetBundle。

使用场景

  • 大型游戏中分模块加载资源。
  • 需要频繁更新内容的在线游戏。
  • 跨平台项目中共享资源。

AssetBundle 的打包

在使用AssetBundle之前,开发者需要将资源打包成AssetBundle文件。打包过程通常在Unity编辑器中完成,使用BuildPipeline API。

如何打包

Unity提供了BuildPipeline.BuildAssetBundles方法来完成打包:

BuildPipeline.BuildAssetBundles("Assets/AssetBundles", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
  • 参数一:输出路径,指定AssetBundle文件保存的目录(如"Assets/AssetBundles")。
  • 参数二:打包选项,用于控制打包行为(详见下文)。
  • 参数三:目标平台,例如BuildTarget.StandaloneWindows(Windows平台)或BuildTarget.Android(Android平台)。

运行这段代码后,Unity会根据资源配置生成AssetBundle文件。

设置资源归属

在Unity编辑器中,开发者需要为每个资源指定它所属的AssetBundle:

  1. 选中资源(例如一个预制体或纹理)。
  2. 在Inspector窗口底部,找到"AssetBundle"下拉菜单。
  3. 输入或选择一个AssetBundle名称(例如"ui"或"characters")。

注意

  • 名称区分大小写,例如"UI"和"ui"会被视为不同的AssetBundle。
  • 未指定AssetBundle的资源不会被打包。

打包策略

根据项目需求,可以采用不同的打包策略:

  • 按类型打包:将所有纹理打包到一个AssetBundle,所有预制体打包到另一个AssetBundle。
  • 按功能打包:将某个UI界面的所有资源打包到一个AssetBundle。
  • 按场景打包:将一个场景的所有资源打包到一个独立的AssetBundle。

打包选项(BuildAssetBundleOptions)

BuildAssetBundleOptions枚举提供了多种选项,用于优化打包过程:

  • None:默认选项,不使用任何特殊设置。
  • UncompressedAssetBundle:不压缩AssetBundle,文件较大但加载速度快,适合本地加载。
  • ChunkBasedCompression:使用LZ4压缩,文件较小且加载速度较快,是推荐的默认选择。
  • ForceRebuildAssetBundle:强制重新打包,即使资源没有变化,适合调试或确保一致性。
  • DisableWriteTypeTree:不写入类型树信息,减小文件大小,但可能影响跨版本兼容性。

示例:

BuildPipeline.BuildAssetBundles("Assets/AssetBundles", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android);

 这将生成使用LZ4压缩的AssetBundle,适用于Android平台。

打包结果

打包完成后,Unity会在指定目录生成以下文件:

  • 每个AssetBundle文件(例如"ui.bundle")。
  • 一个Manifest文件(例如"AssetBundles"),记录所有AssetBundle的元数据。

AssetBundle 的加载

Unity支持多种加载AssetBundle的方式,开发者可以根据需求选择同步或异步加载,以及从文件、内存或网络加载。

同步加载

直接从文件系统中加载AssetBundle:

AssetBundle bundle = AssetBundle.LoadFromFile("Assets/AssetBundles/ui.bundle");
  • 优点:简单直接,适合小型AssetBundle。
  • 缺点:阻塞主线程,不适合大型文件。

异步加载

使用异步方法加载,避免阻塞主线程:

IEnumerator LoadBundleAsync()
{
    AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync("Assets/AssetBundles/ui.bundle");
    yield return request; // 等待加载完成
    AssetBundle bundle = request.assetBundle;
}
  • 优点:不会卡顿,适合大型AssetBundle。
  • 使用场景:后台加载或需要显示加载进度的场景。

从内存加载

从字节数组中加载AssetBundle:

byte[] bundleData = File.ReadAllBytes("Assets/AssetBundles/ui.bundle");
AssetBundle bundle = AssetBundle.LoadFromMemory(bundleData);

异步版本:

IEnumerator LoadFromMemoryAsync()
{
    byte[] bundleData = File.ReadAllBytes("Assets/AssetBundles/ui.bundle");
    AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(bundleData);
    yield return request;
    AssetBundle bundle = request.assetBundle;
}

适用场景:从网络下载后直接加载字节数据。

从网络加载

通过URL下载并加载AssetBundle:

IEnumerator LoadFromWeb()
{
    UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle("http://example.com/ui.bundle");
    yield return www.SendWebRequest();
    if (www.result == UnityWebRequest.Result.Success)
    {
        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
    }
    else
    {
        Debug.LogError("加载失败: " + www.error);
    }
}

适用场景:热更新或在线分发资源

加载AssetBundle中的资源

加载AssetBundle后,可以从中提取具体资源:

GameObject prefab = bundle.LoadAsset<GameObject>("MyPrefab");

异步加载资源:

IEnumerator LoadAssetAsync(AssetBundle bundle)
{
    AssetBundleRequest request = bundle.LoadAssetAsync<GameObject>("MyPrefab");
    yield return request;
    GameObject prefab = request.asset as GameObject;
}

加载所有资源:

UnityEngine.Object[] assets = bundle.LoadAllAssets();

注意:资源名称需与打包时一致,且区分大小写。


依赖管理

AssetBundle之间可能存在依赖关系,例如一个预制体引用了另一个AssetBundle中的纹理。Unity通过Manifest文件管理这些依赖。

Manifest 文件

打包时,Unity会生成一个Manifest文件(例如"AssetBundles"),记录所有AssetBundle的元数据,包括依赖关系、哈希值等。

加载Manifest

AssetBundle manifestBundle = AssetBundle.LoadFromFile("Assets/AssetBundles/AssetBundles");
AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

查看依赖关系

通过AssetBundleManifest获取某个AssetBundle的依赖:

string[] dependencies = manifest.GetAllDependencies("ui.bundle");
foreach (string dependency in dependencies)
{
    Debug.Log("依赖: " + dependency);
}

加载依赖

在加载目标AssetBundle之前,必须先加载其依赖:

string[] dependencies = manifest.GetAllDependencies("ui.bundle");
foreach (string dependency in dependencies)
{
    AssetBundle.LoadFromFile(Path.Combine("Assets/AssetBundles", dependency));
}
AssetBundle uiBundle = AssetBundle.LoadFromFile("Assets/AssetBundles/ui.bundle");

注意:如果依赖未加载,资源可能无法正确显示(例如纹理缺失)。


卸载AssetBundle

为了释放内存,开发者需要在不再使用AssetBundle时卸载它。

卸载方法

使用AssetBundle.Unload:

bundle.Unload(true);
  • true:卸载AssetBundle及其中的所有资源。
  • false:仅卸载AssetBundle,保留已加载的资源实例。

卸载注意事项

  • Unload(true)
    • 确保资源不再被场景引用,否则会导致引用丢失(例如场景中的对象变成“粉红色”)。
  • Unload(false)
    • 已加载的资源(如实例化的预制体)会继续存在,直到没有引用时被垃圾回收。
  • 内存管理
    • 使用Unity Profiler检查内存占用,确保卸载生效。

示例

GameObject prefab = bundle.LoadAsset<GameObject>("MyPrefab");
GameObject instance = Instantiate(prefab);
bundle.Unload(false); // 保留实例
Destroy(instance); // 销毁实例后,资源才会被完全释放

AssetBundle 与热更新

AssetBundle是实现热更新的核心工具,允许开发者更新游戏内容而无需重新发布整个游戏。

热更新流程

  1. 打包更新资源:将更新的资源打包成新的AssetBundle。
  2. 上传服务器:将AssetBundle上传到远程服务器。
  3. 客户端下载:客户端通过网络下载并加载这些AssetBundle。

示例

IEnumerator UpdateBundle()
{
    UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle("http://example.com/new_ui.bundle");
    yield return www.SendWebRequest();
    AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
    GameObject prefab = bundle.LoadAsset<GameObject>("NewUIPrefab");
    Instantiate(prefab);
}

版本管理

为AssetBundle分配版本号,客户端通过比较版本号决定是否需要更新。Manifest文件中的哈希值可用于版本控制:

string bundleHash = manifest.GetAssetBundleHash("ui.bundle").ToString();

客户端保存本地AssetBundle的哈希值,与服务器对比,若不同则下载更新。

Addressables 系统

Unity推出了Addressable Asset System,它是AssetBundle的高级封装,提供以下改进:

  • 更简单的API。
  • 自动依赖管理。
  • 内置版本控制。 推荐在现代项目中使用Addressables替代手动管理AssetBundle。

AssetBundle 的优缺点

优点

  • 动态加载:按需加载资源,优化性能。
  • 热更新:支持动态更新游戏内容。
  • 资源复用:可以在不同场景或项目中复用。

缺点

  • 管理复杂:需要手动处理打包、加载和依赖关系。
  • 依赖问题:加载顺序错误可能导致资源缺失。
  • 版本兼容性:不同Unity版本生成的AssetBundle可能不兼容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值