打包工具AssetBundleBrowser
工具展示:
属性说明:
AssetBundle加载资源
同步加载
同步加载assetbundle资源用分为以下两步
- 从指定目录中加载AB包
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "加载的ab包名字");
注意:
加载AB包,注意AB包不能重复加载,否则会报错
- 加载AB包中资源的三种方法
-
GameObject obj1 = ab.LoadAsset("Cube") as GameObject;//不推荐使用(会分不清同名的不同类型资源)
-
GameObject obj2 = ab.LoadAsset<GameObject>("Cube");
-
GameObject obj3 = ab.LoadAsset("Cube", typeof(GameObject)) as GameObject;
异步加载
void Start()
{
StartCoroutine(LoadABRes("image", "image"));
}
IEnumerator LoadABRes(string ABName, string resName)
{
AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + ABName);
yield return abcr;
AssetBundleRequest abq = abcr.assetBundle.LoadAssetAsync(resName, typeof(Sprite));
yield return abq;
Image.sprite = abq.asset as Sprite;
}
卸载所有加载的AB包:
注意ture会把加载的资源给卸载了,一般参数为false
AssetBundle.UnloadAllAssetBundles(false);
卸载单个包:
ab.Unload(false);
总结
- 使用AssetBundle动态加载资源首先要获取AssetBundle对象,第二步才是从AssetBundle中加载目标资源。
- 要在运行时加载AssetBundle对象主要可以分为两大类途径:
- a先获取WWW对象,再通过WWW.assetBundle获取AssetBundle对象(已弃用)
- b直接获取AssetBundle(5.3之后 LoadFromFile,LoadFromMemory,LoadFromMemoryAsync并增加了LoadFromFileAsync)
- Unity提供了三个不同的API从AssetBundles加载UnityEngine.Objects,这些API都绑定到AssetBundle对象上,并且这些API具有同步和异步变体:
- LoadAsset (LoadAssetAsync)
- LoadAllAssets (LoadAllAssetsAsync)
- LoadAssetWithSubAssets (LoadAssetWithSubAssetsAsync)
- 并且这些API的同步版本总是比异步版本快至少一个帧(其实是因为异步版本为了确保异步,都至少延迟了1帧),异步加载每帧会加载多个对象,直到它们的时间切片切出。
AssetBundle加载依赖资源
为什么要加载依赖资源:
一个资源身上用到了别的AB包的资源,如果只加载了自己的AB包,会出现资源丢失的情况,需要把依赖包一起加载才会正常,如果重复加载又会报错
方法1:
- 知道依赖于哪些包,直接加载
- 实际开发中不可能知道依赖包,就算知道这样加载也十分的麻烦,不利于后期修改
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "ui");
AssetBundle ab2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "image");
GameObject obj1 = ab.LoadAsset("Canvas", typeof(GameObject)) as GameObject;
Instantiate(obj1);
方法2:
- 更加通用的方法,就算不知道资源依赖于哪些包,也可以通过下面方法获取依赖文件并进行加载
- 如何操作:加载主包中的固定文件,从固定文件中得到依赖信息
//1.加载主包
AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "pc");
//2.加载主包中的固定文件
AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//3.从固定文件中得到依赖信息
string[] strs = abManifest.GetAllDependencies("ui");
for (int i = 0; i < strs.Length; i++)
{
AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + strs[i]);
}
//4.加载需要加载资源的包
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "ui");
GameObject obj1 = ab.LoadAsset("Canvas", typeof(GameObject)) as GameObject;
Instantiate(obj1);
练习:AssetBundle管理器
工具类,提供同步、异步加载资源的三种方法方便使用
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class ABMgr : MonoSingleton<ABMgr>
{
//开发目的:让外部更方便的进行资源加载
//AB包不能重复加载,用字典来存储加载过的AB包
private AssetBundle mainAB = null;
private AssetBundleManifest mainfest = null;
private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
/// <summary>
/// ab包存放路径
/// </summary>
private string PathUrl
{
get
{
return Application.streamingAssetsPath + "/";
}
}
/// <summary>
/// 主包名 根据平台不同选择不同的主包名
/// </summary>
private string MainName
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "pc";
#endif
}
}
/// <summary>
/// 加载ab包
/// </summary>
/// <param name="abName"></param>
private void LoadAB(string abName)
{
if (mainAB == null)
{
mainAB = AssetBundle.LoadFromFile(PathUrl + MainName);
mainfest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
AssetBundle ab = null;
string[] strs = mainfest.GetAllDependencies(abName);
for (int i = 0; i < strs.Length; i++)
{
if (!abDic.ContainsKey(strs[i]))
{
ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
abDic.Add(strs[i], ab);
}
}
if (!abDic.ContainsKey(abName))
{
ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
}
/// <summary>
/// 同步加载
/// 不指定类型
/// </summary>
/// <param name="abName"></param>
/// <param name="resName"></param>
public Object LoadRes(string abName,string resName)
{
LoadAB(abName);
Object obj = abDic[abName].LoadAsset(resName);
if (obj is GameObject)
{
return Instantiate(obj);
}
else
{
return obj;
}
}
/// <summary>
/// 同步加载
/// 指定类型
/// </summary>
/// <param name="abName"></param>
/// <param name="resName"></param>
/// <param name="type"></param>
/// <returns></returns>
public Object LoadRes(string abName, string resName, System.Type type)
{
LoadAB(abName);
Object obj = abDic[abName].LoadAsset(resName,type);
if (obj is GameObject)
{
return Instantiate(obj);
}
else
{
return obj;
}
}
/// <summary>
/// 同步加载
/// 泛型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="abName"></param>
/// <param name="resName"></param>
/// <returns></returns>
public T LoadRes<T>(string abName, string resName) where T : Object
{
LoadAB(abName);
T obj = abDic[abName].LoadAsset<T>(resName);
if (obj is GameObject)
{
return Instantiate(obj);
}
else
{
return obj;
}
}
/// <summary>
/// 异步加载
/// 不指定类型
/// </summary>
/// <param name="abName"></param>
/// <param name="resName"></param>
/// <param name="callBack"></param>
public void LoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
StartCoroutine(IELoadResAsync(abName, resName, callBack));
}
private IEnumerator IELoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
LoadAB(abName);
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);
yield return abr;
if (abr.asset is GameObject)
{
callBack(Instantiate(abr.asset));
}
else
{
callBack(abr.asset);
}
}
/// <summary>
/// 异步加载
/// 指定类型
/// </summary>
/// <param name="abName"></param>
/// <param name="resName"></param>
/// <param name="type"></param>
/// <param name="callBack"></param>
public void LoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
StartCoroutine(IELoadResAsync(abName, resName, type, callBack));
}
private IEnumerator IELoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
LoadAB(abName);
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName,type);
yield return abr;
if (abr.asset is GameObject)
{
callBack(Instantiate(abr.asset));
}
else
{
callBack(abr.asset);
}
}
/// <summary>
/// 异步加载
/// 泛型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="abName"></param>
/// <param name="resName"></param>
/// <param name="callBack"></param>
public void LoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T : Object
{
StartCoroutine(IELoadResAsync<T>(abName, resName, callBack));
}
private IEnumerator IELoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T : Object
{
LoadAB(abName);
AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
yield return abr;
if (abr.asset is GameObject)
{
callBack(Instantiate(abr.asset) as T);
}
else
{
callBack(abr.asset as T);
}
}
/// <summary>
/// 单个包卸载
/// </summary>
/// <param name="abName"></param>
public void UnLoad(string abName)
{
if (abDic.ContainsKey(abName))
{
abDic[abName].Unload(false);
abDic.Remove(abName);
}
}
/// <summary>
/// 所有包卸载
/// </summary>
public void ClearAll()
{
AssetBundle.UnloadAllAssetBundles(false);
abDic.Clear();
mainAB = null;
mainfest = null;
}
}
using UnityEngine;
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
public bool global = true;
static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = (T)FindObjectOfType<T>();
}
return instance;
}
}
/// <summary>
/// 在monosingleton中写awake后
/// 子类也不能使用awake了
/// 同理如果要用start需要用重写的方法
/// </summary>
void Awake()
{
if (global)
{
if (instance != null && instance != this.gameObject.GetComponent<T>())
{
Destroy(this.gameObject);
return;
}
DontDestroyOnLoad(this.gameObject);
instance = this.gameObject.GetComponent<T>();
}
this.OnStart();
}
protected virtual void OnStart()
{
}
}
资料参考
https://www.bilibili.com/video/BV1LD4y1m7kF
Comments | 0 条评论