1、前言
AssetBundle是Unity中的一种资源包,可以包含了我们用到的几乎所有资源,实现资源的热更。
2、文件格式的类型
我们打包AssetBundle后,Unity3D会根据文件的后缀名将文件转换为特定的类型对象存储起来,我们后期获取时需要根据这些类型取出打包的数据,这里简单记录下不同后缀文件打包后的类型。
-
文本格式
支持后缀:txt、xml;
打包后的类型:TextAsset,数据保存在TextAsset的text属性中。 -
二进制格式
支持后缀:bytes;
打包后的类型:TextAsset,数据保存在TextAsset的bytes属性中。 -
预制件格式
支持后缀:prefab;
打包后的类型:GameObject,加载后还需要调用Instantiate函数实例化才能使用。 -
图片格式
支持后缀:bmp、jpg、png;
打包后的类型:Texture2D、Sprite。 -
音乐格式
支持后缀:aiff、wav、mp3、ogg;
打包后的类型:AudioClip。
转载链接:https://www.cnblogs.com/hammerc/p/4785394.html
3、打包
AssetBundle打包要注意资源之间的依赖关系,生成尽量少的bundle数目和尽可能不产生冗余资源。以下示例是以文件夹为一个bundle,并检测依赖资源也按这种方式打包。资源文件夹Resources目录下
[MenuItem("AssetBundle/Window")]
public static void PackWindow()
{
//EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows);
StartPack(BuildTarget.StandaloneWindows, "Assets/Resources", Application.streamingAssetsPath);
}
private static void StartPack(BuildTarget target, string path, string outPath)
{
if (!Directory.Exists(path))
return;
if (!Directory.Exists(outPath))
Directory.CreateDirectory(outPath);
AssetBundleBuild[] builders = GetAllAssetBundleBuild(path);
BuildPipeline.BuildAssetBundles(outPath, builders, BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DisableWriteTypeTree, target);
Debug.Log("AssetBundle ok !");
}
public static string StandardizedPath(string path)
{
return path.Replace("\\", "/");
}
private static AssetBundleBuild[] GetAllAssetBundleBuild(string path)
{
Dictionary<string, string> builderDic = new Dictionary<string, string>();
List<AssetBundleBuild> builders = new List<AssetBundleBuild>();
GetBuildersInfo(path, builderDic);
foreach (KeyValuePair<string, string> keyValuePair in builderDic)
{
string assetName = keyValuePair.Key;
string bundleName = keyValuePair.Value + ".ab";
AssetBundleBuild build = new AssetBundleBuild();
build.assetBundleName = bundleName.ToLower();
string[] assets = new string[1];
assets[0] = assetName;
build.assetNames = assets;
builders.Add(build);
}
return builders.ToArray();
}
private static void GetBuildersInfo(string path, Dictionary<string, string> dic)
{
if (string.IsNullOrEmpty(path) || dic == null)
return;
string[] dirs = Directory.GetDirectories(path);
if (dirs != null && dirs.Length > 0)
{
for (int i = 0; i < dirs.Length; i++)
{
GetBuildersInfo(dirs[i], dic);
}
}
else
{
string[] files = Directory.GetFiles(path);
if (files == null || files.Length == 0)
{
Debug.Log("无资源文件夹 " + path);
return;
}
foreach (string file in files)
{
string standardlizedFile = StandardizedPath(file);
if (standardlizedFile.EndsWith(".meta"))
continue;
if (!dic.ContainsKey(standardlizedFile))
dic.Add(standardlizedFile, StandardizedPath(path));
//依赖包处理
string[] depends = AssetDatabase.GetDependencies(new string[1] { standardlizedFile });
for (int i = 0; i < depends.Length; i++)
{
string dependAssetName = StandardizedPath(depends[i]);
if (!dic.ContainsKey(dependAssetName))
dic.Add(depends[i], System.IO.Path.GetDirectoryName(dependAssetName));
}
}
}
}
打包完成bundle资源如下:
具体资源怎么打包bundle,每个人都可以有自己的策略,但是对依赖资源要很好的处理,尽量减少冗余资源。
注意MainAsset这个文件,它里面包我们需要的信息后面会用到。
4、加载
ab包加载主要分为两大类,同步加载和异步加载,同步加载直接获得资源,使用比较方便,但是ab包过大会造成卡顿,异步加载很好的解决了这个问题。以下已同步加载为例,注意在加载ab包时,要先加载它所有的依赖包。
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AssetBundleManager : MonoBehaviour {
public static AssetBundleManager Instance;
private Dictionary<string, AssetBundle> assetBundleDic = new Dictionary<string, AssetBundle>();
private AssetBundleManifest manifest;
private string manifestName = "StreamingAssets";
// Use this for initialization
void Awake()
{
if (Instance != null)
return;
Instance = this;
DontDestroyOnLoad(gameObject);
}
void Start () {
string path = Application.streamingAssetsPath + "/" + manifestName;
if (File.Exists(path))
{
AssetBundle bundle = AssetBundle.LoadFromFile(path);
if (bundle)
manifest = bundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
}
// Update is called once per frame
void Update () {
}
public GameObject LoadPrefab(string asset)
{
return LoadAsset<GameObject>(asset.ToLower());
}
private T LoadAsset<T>(string asset) where T : UnityEngine.Object
{
try
{
T result = null;
string assetName = System.IO.Path.GetDirectoryName(asset) + ".ab";
AssetBundle ab = GetContainsAssetBundle(assetName);
if (null == ab)
ab = LoadAssetBundleAndDependencies(assetName);
if (ab != null)
result = ab.LoadAsset<T>(asset);
return result;
}
catch (System.Exception ex)
{
Debug.LogError("AssetBundleManager.LoadAsset is failed!" + asset + " : " + ex.Message);
}
return null;
}
private AssetBundle GetContainsAssetBundle(string asset)
{
if (assetBundleDic.ContainsKey(asset))
return assetBundleDic[asset];
return null;
}
private AssetBundle LoadAssetBundleAndDependencies(string asset)
{
if (manifest == null)
{
Debug.LogWarning("AssetBundleManifest loading failed! ");
return null;
}
string[] dependents = manifest.GetDirectDependencies(asset);
for (int i = 0; i < dependents.Length; i++)
{
if (LoadAssetBundleAndDependencies(dependents[i]) == null)
{
Debug.LogWarning(asset + " Dependencies " + dependents[i] + " loading failed !");
return null;
}
}
return LoadAssetBundle(asset);
}
private AssetBundle LoadAssetBundle(string asset)
{
AssetBundle bundle = GetContainsAssetBundle(asset);
if (bundle == null)
{
string path = Application.streamingAssetsPath + "/" + asset;
if (File.Exists(path))
{
bundle = AssetBundle.LoadFromFile(path);
assetBundleDic.Add(asset, bundle);
}
else
{
Debug.LogWarning(asset + " not Exists !");
}
}
return bundle;
}
}
异步加载大致流程基本相同,这里不再介绍。
ab包卸载自己把握时间
AssetBundle.Unload(false),卸载AB包资源,同时保留内存中已加载的资源;
AssetBundle.Unload(true),卸载AB包资源,同时卸载内存中已加载的资源,会造成资源的丢失