AssetBundle
设置资源AB
基本上unity所包含的资源文件,除了脚本文件都可以设置成ab资源。
生成AB资产
生成AB有两种方式
- 自定义打包
- AssetBundles-Browser-master插件
- 预览AB
这里使用插件打包,对于目前所有ab资源一目了然,如有ab设置错误也会有错误提示,我们已经设置好ab资源用它打开如图
正是因为unity支持‘/’来分层,所以我们用文件层次来设置ab名称
才使得对应ab包层级目录结构清晰明确
2. 打包设置
根据当前ab资源选择不同压缩模式比较
压缩模式 | UnCompression | LZ4 | LZMA |
---|---|---|---|
Andriod平台大小 | 325kb | 160kb | 119kb |
- LZ4 解压读取速度快(推荐)
- LZMA 压缩率高,文件占用空间小,解压比较慢
获取AB加载
大致流程图示
下面示例从服务器中获取 tom ab资源一系列流程
要测试在服务中的ab资源
测试代码
1.连接服务器,获取主依赖
调用入口
StartCoroutine(GetDepends(host, "AB_Andriod_LZ4"));
具体实现
/// <summary>
/// 服务器地址
/// </summary>
string host = @"https://ab-test-1258795305.cos.ap-shanghai.myqcloud.com/";
/// <summary>
/// ab-依赖
/// </summary>
public Dictionary<string/*ab path*/, AB_DATA> dic_AB = new Dictionary<string, AB_DATA>();
/// <summary>
/// 获取主依赖,本地存储依赖关系,下载全部ab
/// </summary>
/// <param name="host_path">服务器根地址</param>
/// <param name="dir_name">服务器下ab根文件名,以及主ab文件名称</param>
/// <returns></returns>
IEnumerator GetDepends(string host_path, string dir_name)
{
dic_AB.Clear();
//目录跟路径
string root_path = host_path + "/" + dir_name;
//获取主ab,拿到manifest获取依赖关系
AssetBundleManifest assetBundleManifestServer = null; //服务器 总的依赖关系
UnityWebRequest ServerManifestWWW = UnityWebRequestAssetBundle.GetAssetBundle(root_path + "/" + dir_name);
Debug.Log("HTTP : " + ServerManifestWWW.url.ToString());
yield return ServerManifestWWW.SendWebRequest();
assetBundleManifestServer = (AssetBundleManifest)DownloadHandlerAssetBundle.GetContent(ServerManifestWWW).LoadAsset("AssetBundleManifest");
//存储各依赖关系
string[] depends_name = assetBundleManifestServer.GetAllAssetBundles();
for (int i = 0; i < depends_name.Length; i++)
{
AB_DATA ab_data = new AB_DATA();
ab_data.name = depends_name[i];
UnityWebRequest target_uwq = UnityWebRequestAssetBundle.GetAssetBundle(Path.Combine(root_path, ab_data.name));
yield return target_uwq.SendWebRequest();
if (target_uwq.isDone)
{
//下载ab到本地
StartCoroutine(DownLoadAssetBundelAbdSave(Path.Combine(root_path, ab_data.name)));
//depends
var depends = assetBundleManifestServer.GetAllDependencies(ab_data.name);
ab_data.depends_name = new string[depends.Length];
for (int j = 0; j < depends.Length; j++)
{
ab_data.depends_name[j] = depends[j];
}
dic_AB.Add(depends_name[i], ab_data);
}
}
}
2.缓存已下载的ab资源
/// <summary>
/// 下载AB文件并保存到本地
/// </summary>
/// <returns></returns>
IEnumerator DownLoadAssetBundelAbdSave(string url)
{
WWW www = new WWW(url);
yield return www;
if (www.isDone)
{
//表示资源下载完毕使用IO技术把www对象存储到本地
SaveAssetBundle(Path.GetFileName(url), www.bytes, www.bytes.Length);
}
}
/// <summary>
/// 存储AB文件到本地
/// </summary>
private void SaveAssetBundle(string fileName, byte[] bytes, int count)
{
string dir_path = Application.persistentDataPath + "/" + fileName;
Debug.Log("存储路径 : " + dir_path);
Stream sw = null;
FileInfo fileInfo = new FileInfo(dir_path);
sw = fileInfo.Create();
sw.Write(bytes, 0, count);
sw.Flush();
sw.Close();
sw.Dispose();
Debug.Log(fileName + "下载并存储完成");
}
3.从本地磁盘读取ab并实例化
调用入口
private void LoadStream_OnClick()
{
//设置要加载的目标物体名
string ab_name = "tom.prefab";
string dir_path = Application.persistentDataPath + "/" + ab_name;
//从已缓存的字节文件中加载tom
StartCoroutine(LoadABFormStream(dir_path));
//加载tom所需的依赖
string[] ad_names = dic_AB[ab_name].depends_name;
for (int i = 0; i < ad_names.Length; i++)
{
string dir_path_depends = Path.Combine(Application.persistentDataPath, ad_names[i]);
//加载依赖时,直接加载出其ab包即可,不需要分解其依赖类型再去实例,unity自会处理
AssetBundle.LoadFromFile(dir_path_depends);
//所以下面部分就不需要了
// StartCoroutine(LoadABFormStream(dir_path_depends));
}
}
相关方式实现
/// <summary>
/// 从字节文件读取ab,并且实例化
/// </summary>
/// <param name="dir_path"></param>
/// <returns></returns>
IEnumerator LoadABFormStream(string dir_path)
{
FileStream fileStream = new FileStream(dir_path, FileMode.Open, FileAccess.Read);
AssetBundleCreateRequest request = AssetBundle.LoadFromStreamAsync(fileStream);
yield return request;
AssetBundle myLoadedAssetBundle = request.assetBundle;
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
yield break;
}
//实例化ab
InstanceAB_FormAssetBundle(myLoadedAssetBundle, myLoadedAssetBundle.name);
fileStream.Close();
}
private void InstanceAB_FormAssetBundle(AssetBundle assetBundle, string obj_name)
{
Object gameObject = null;
if (obj_name.Contains(".mat"))
{
gameObject = assetBundle.LoadAsset<Material>(obj_name);
Instantiate<Material>((Material)gameObject);
}
else if (obj_name.Contains(".prefab"))
{
gameObject = assetBundle.LoadAsset<GameObject>(obj_name);
Instantiate<GameObject>((GameObject)gameObject);
}
}