AssetBundle详解

一:什么是AssetBundle?

AssetBundle就是一个资源捆绑包,就是我们常说的AB包,一个AB中可能包含多个文件(模型、贴图、材质、预制体、声音、场景等)。

二:AssetBundle的优点

1、可以放在任意可读可写的文件夹内,在游戏运行时进行加载资源,从而减少安装包的大小。

2、可以实现资源的热更新。

3、有助于更有效的管理和优化资源。

三:如何使用AssetBundle

1、构建AssetBundle

我们在场景中创建一个球体,然后把他做成预制体。预览这个预制体,我们观察左下角的AssetBundle。

点击下拉框→new→输入路径或者名字(支持目录形式)。

如果有两个资源选择了同一个路径,那么他们会被打成一个包。

我们实现一个手动Bulid的功能脚本

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

public class BulidAssetBundle : MonoBehaviour
{
	[MenuItem("Framework/AssetBundleHelper/Build", false, 1)]
	private static void BuildAssetBundle()
	{
		string path = "Assets/AssetBundles";
		if (!Directory.Exists(path))
		{
			Directory.CreateDirectory(path);
		}

		BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
		AssetDatabase.Refresh(); //刷新工程目录的缓存
	}
}

我们进行第一次构建,会生成以下文件:

其中sphere.ab是我们构建出来的AssetBundle本地,.manifest的文件是这个AssetBundle对应的清单文件。

2、加载AssetBundle

加载AssetBundle有四种方式,分别是从本地文件加载、从流加载、从内存加载以及从远程服务器加载。它们分别对应如下几个API

  • AssetBundle.LoadFromFile从本地加载
  • AssetBundle.LoadFromMemory从内存中加载
  • AssetBundle.LoadFromStream从流中加载
  • UnityWebRequestAssetBundle.GetAssetBundle从远程服务器加载(也可以从本地加载)
AssetBundle.LoadFromFile

如果AssetBundle未压缩或采用了数据块(LZ4)压缩方式,LoadFromFile 将直接从磁盘加载AssetBundle。使用此方法加载完全压缩 (LZMA) 的AssetBundle将首先解压缩AssetBundle,然后再将其加载到内存中。

// 同步方式
private static void LoadMethodSync()
{
	string path = "Assets/AssetBundles/sphere";
	AssetBundle assetBundle = AssetBundle.LoadFromFile(path);
	GameObject sphere= assetBundle.LoadAsset<GameObject>("Sphere");
	Instantiate(sphere);
}
// 异步方式
IEnumerator LoadMethodAsync()  
{  
    string path = "Assets/AssetBundles/sphere";  
    AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);  
    yield return request;  
    var sphere= request.assetBundle.LoadAsset<GameObject>("Sphere");  
    Instantiate(sphere);  
}
AssetBundle.LoadFromMemory

该方法传入一个包含AssetBundle数据的字节数组。也可以根据需要传递CRC校验码。如果捆绑包采用的是LZMA压缩方式,将在加载时解压缩AssetBundle。LZ4 压缩包则会以压缩状态加载。当下载的是加密数据并需要从未加密的字节创建AssetBundle时会用到。

// 同步方法
private static void LoadMethodSync()  
{  
    string path = "Assets/AssetBundles/sphere";  
    AssetBundle assetBundle = AssetBundle.LoadFromMemory(File.ReadAllBytes(path));  
    Instantiate(sphere);  
}
// 异步方法
IEnumerator LoadMethodAsync()  
{  
    string path = "Assets/AssetBundles/sphere";  
    AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));  
    yield return request;  
    var sphere= request.assetBundle.LoadAsset<GameObject>("Sphere");  
    Instantiate(sphere);  
}
AssetBundle.LoadFromStream

从托管Stream加载AssetBundle。如果是LZMA压缩,则将数据解压缩到内存。如果是未压缩或使用块压缩的捆绑包,则直接从Stream读取。需要注意的是,在加载AssetBundle或其中的资源时,不应该释放Stream资源,应该在AssetBundle.Unload之后再释放。相比于从内存加载,从流加载的优势是加载加密资源时,占用的内存较小。

// 同步方法
private static void LoadMethodSync()
{
	AssetBundle.UnloadAllAssetBundles(true);
	string path = "Assets/AssetBundles/sphere";
	
	FileStream stream = new FileStream(path, FileMode.Open,FileAccess.Read);
	AssetBundle assetBundle = AssetBundle.LoadFromStream(stream);
	GameObject sphere= assetBundle.LoadAsset<GameObject>("Sphere");
	Instantiate(sphere);
	assetBundle.Unload(false);
	stream.Close();
}
// 异步方法
IEnumerator LoadMethodAsync()
{
	string path = "Assets/AssetBundles/sphere";
	FileStream stream = new FileStream(path, FileMode.Open,FileAccess.Read);
	AssetBundleCreateRequest request = AssetBundle.LoadFromStreamAsync(stream);
	yield return request;
	var sphere= request.assetBundle.LoadAsset<GameObject>("Sphere");
	Instantiate(sphere);
	request.assetBundle.Unload(false);
	stream.Close();
}
UnityWebRequestAssetBundle.GetAssetBundle

该方法会创建经过优化的 UnityWebRequest,以通过 HTTP GET 下载AssetBundle。请求成功后,使用DownloadHandlerAssetBundle方法将数据流式传输到缓冲区并解压缩。与一次性下载所有数据相比,这种方式节省了很多内存。[如果加载本地数据,需要在路径前加上file://]

IEnumerator LoadMethodAsync()
{
	string path = @"[远程资源路径]";

	UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(path);
	yield return request.SendWebRequest();
	AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(request);
	GameObject sphere= assetBundle.LoadAsset<GameObject>("Sphere");
	Instantiate(sphere);

}
3、加载AssetBundle
string path = "Assets/AssetBundles/sphere";
AssetBundle assetBundle = AssetBundle.LoadFromFile(path);

// 同步加载指定资源
GameObject sphere= assetBundle.LoadAsset<GameObject>("Sphere");
// 异步加载指定资源
AssetBundleRequest request1 = assetBundle.LoadAssetAsync<GameObject>("Sphere");
// 同步加载所有资源
UnityEngine.Object[] objs = assetBundle.LoadAllAssets();
// 异步加载所有资源
AssetBundleRequest request2 = assetBundle.LoadAllAssetsAsync();
4、加载AssetBundle

当你不在使用AssetBundle加载出来的资源时,需要及时将他卸载掉,来释放他占用的内存空间。

核心API:AssetBundle.Unload(bool)

默认传true,表示卸载AssetBundle本身以及从AssetBundle加载出来的全部资源,建议传true,不然会导致资源无法匹配,生成多份资源,造成内存资源的浪费。

四:AssetBundle依赖关系

例如A包是一个材质包,B包是一个贴图包,A包中的材质引用B包中的贴图,如果不加载B包只加载A包,则A包中材质的贴图是丢失的。

五:AssetBundle分组策略

  • 逻辑实体分组 
    一个UI界面或所有UI界面一个包(贴图、布局信息)
    一个角色或所有角色一个包(模型、动画)
    场景之间共享的资源一个包
  • 类型分组
    所有音频资源一个包
    所有模型资源一个包
    所有材质资源一个包
  • 并发内容分组
    同一时间内需要用到的资源一个包
    一个关卡所需的资源一个包
    一个场景所需的资源一个包

合理的分组策略能有效处理资源包依赖错乱的问题。

六:工具使用

  • Analyze tool: 可以查看资源冗余以及系统如何打包资源,可以通自定义规则去生成额外的报告信息。
检查资源的冗余依赖
检查Resources到Addressables的冗余依赖
检查Scene到Addressables的冗余依赖
Bundle Layout 预览

参考:

AssetBundle - Unity 手册

Addressables | Addressables | 1.19.19

  • 35
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值