源码工程路径
这次我们把上节中的立方体Cube从AssetBundle中加载出来,实例化立方体;然后把材质m_Material2从AssetBundle加载出来,并把立方体Cube的材质换成m_Material2
我们新加了两个资源,一个是纹理detail2,一个是材质m_Material2
先看一下效果
讲一下思路,代码不详细讲,太多了,也都挺简单的,原理在上一节都讲过了,原码都会贴出来
首先我们创建了五个脚本
IABManifestLoader.cs
主要用来加载Manifest文件
IABRelationManager.cs
保存单个AssetBundle和该它所依赖的AssetBundle和依赖他的AssetBundle,对单个AssetBundle进行的操作都在这个文件中(得到单个资源,卸载单个资源等)
IABManager.cs
对所有的AssetBundle进行管理,主要有三个数据结构
正在加载的AssetBundle放在preLoadHelper中避免重复加载
加载完成的AssetBundle放在loadHelper中
已经从ab中load出具体资源放在loadObj中
我们想要加载一个具体资源比如立方体Cube时,先从loadObj中找,如果没有的话再从loadHelper中找,在没有的话再根据AssetBundle名字和地址用WWW下载
当我们把立方体Cube加载出来后用回调的方式返回上层,然后我们就可以得到Cube,然后我们就可以把Cube实例化出来了。
加载具体资源的代码
public void LoadSingleObject(string bundleName, string resName, LoadObjectCallBack callBack)
{
//表示 是否已经缓存了物体
if (loadObj.ContainsKey(bundleName))
{
AssetResObj tmpRes = loadObj[bundleName];
Object tmpObj = tmpRes.GetResObj(resName);
if (tmpObj != null) {
callBack(tmpObj);
return;
}
}
//表示bundle已经加载过
if (loadHelper.ContainsKey(bundleName))
{
LoadObjectFromBundle(bundleName, resName, callBack);
}
//加载bundle
else
{
StartCoroutine(LoadAssetBundle(bundleName, (tmpBundleName) => {
LoadObjectFromBundle(bundleName, resName, callBack);
}));
}
}
其中TestLoad.cs是测试文件,IPathTools是个工具类
完整代码
IABManifestLoader.cs
using UnityEngine;
using System.Collections;
public class IABManifestLoader {
public AssetBundleManifest assetManifest;
public string manifesetName;
private bool isLoadFinish;
public AssetBundle manifestLoader;
static IABManifestLoader instance = null;
public static IABManifestLoader Instance {
get {
if (instance == null) {
instance = new IABManifestLoader();
}
return instance;
}
}
public IABManifestLoader()
{
assetManifest = null;
manifestLoader = null;
isLoadFinish = false;
manifesetName = IPathTools.GetABManifestName();
}
public IEnumerator LoadManifeset() {
manifesetName = IPathTools.StandardPath(manifesetName);
Debug.Log("manifesetName "+ manifesetName);
WWW manifest = new WWW(manifesetName);
yield return manifest;
if (!string.IsNullOrEmpty(manifest.error))
{
Debug.Log(manifest.error);
}
else {
if (manifest.progress >= 1.0f) {
manifestLoader = manifest.assetBundle;
assetManifest = manifestLoader.LoadAsset("AssetBundleManifest") as AssetBundleManifest;
isLoadFinish = true;
Debug.Log("manifest load finish");
}
}
}
public string[] GetDepences(string name) {
return assetManifest.GetAllDependencies(name);
}
public void UnloadManifest() {
manifestLoader.Unload(false); //true
}
public bool IsLoadFinish() {
return isLoadFinish;
}
}
IABRelationManager.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class IABRelationManager {
//依赖关系
List<string> depedenceBundle;
//被依赖关系
List<string> referBundle;
public AssetBundle assetBundle;
string theBundleName;
bool isLoadFinish;
bool canAutoUnload;
public string GetBundleName() {
return theBundleName;
}
public IABRelationManager()
{
depedenceBundle = new List<string>();
referBundle = new List<string>();
}
public bool IsBundleLoadFinish()
{
return isLoadFinish;
}
public void Initial(string bundleName, bool autoUnload = true)
{
isLoadFinish = false;
theBundleName = bundleName;
canAutoUnload = autoUnload;
}
public void SetAssetBundle(AssetBundle bundle) {
assetBundle = bundle;
isLoadFinish = true;
}
public void SetDependences(string[] dependence)
{
if (dependence.Length > 0)
{
depedenceBundle.AddRange(dependence);
}
}
public List<string> GetDependences()
{
return depedenceBundle;
}
//添加被依赖关系
public void AddRefference(string bundleNmae) {
referBundle.Add(bundleNmae);
}
//获取被依赖关系
public List<string> GetRefference() {
return referBundle;
}
public Object GetSingleResource(string resName)
{
return assetBundle.LoadAsset(resName);
}
/// <summary>
///
/// </summary>
/// <param name="bundleName"></param>
/// <returns>表示是否释放了自己</returns>
public bool RemoveReference(string bundleName) {
int index = -1;
for (int i = 0; i < referBundle.Count; i++) {
if (bundleName.Equals(referBundle[i])) {
index = i;
break;
}
}
if (index > -1) {
referBundle.RemoveAt(index);
}
if (referBundle.Count <= 0)
{
return Dispose();
}
return true;
}
#region 有下层提供API
/// <summary>
/// 释放过程
/// </summary>
public bool Dispose() {
if (canAutoUnload)
{
if (assetBundle != null) {
assetBundle.Unload(false);
IABManager.instance.RemoveBundle(theBundleName);
}
return true;
}
else {
return false;
}
}
#endregion
}
IABManager.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
public delegate void LoadAssetBundleCallBack(string bundleName);
public delegate void LoadObjectCallBack(Object o);
//单个物体 存取
public class AssetObj {
public Object obj;
public AssetObj(Object tmpObj) {
obj = tmpObj;
}
public void ReleaseObj() {
Resources.UnloadAsset(obj);
}
}
//相同bundle中的资源都存在这
public class AssetResObj {
public Dictionary<string, AssetObj> resObjs;
public AssetResObj(string name, AssetObj tmp) {
resObjs = new Dictionary<string, AssetObj>();
resObjs.Add(name,tmp);
}
public void AddResObj(string name, AssetObj tmpObj) {
resObjs.Add(name,tmpObj);
}
//释放多个
public void ReleaseAllResObj() {
List<string> keys = new List<string>();
keys.AddRange(resObjs.Keys);
for (int i = 0; i < keys.Count; i++) {
ReleaseResObj(keys[i]);
}
}
//释放单个
public void ReleaseResObj(string name) {
if (resObjs.ContainsKey(name))
{
AssetObj tmpObj = resObjs[name];
tmpObj.ReleaseObj();
}
else {
Debug.Log("release object name is not exit == "+name);
}
}
public Object GetResObj(string name) {
if (resObjs.ContainsKey(name))
{
AssetObj tmpObj = resObjs[name];
return tmpObj.obj;
}
else
{
return null;
}
}
}
//ab加载完成后的回调
public class LoadAssetBundleCallBackManager {
string theBundleName;
List<LoadAssetBundleCallBack> callBacks;
public LoadAssetBundleCallBackManager(string bundleName) {
theBundleName = bundleName;
callBacks = new List<LoadAssetBundleCallBack>();
}
public void AddCallBack(LoadAssetBundleCallBack callBack) {
callBacks.Add(callBack);
}
public void CallBack(string bundleName) {
for (int i = 0; i < callBacks.Count; i++) {
callBacks[i](bundleName);
}
}
}
public class IABManager:MonoBehaviour {
//正在加载的ab
Dictionary<string, IABRelationManager> preLoadHelper = new Dictionary<string, IABRelationManager>();
//已经加载完成的ab
Dictionary<string, IABRelationManager> loadHelper = new Dictionary<string, IABRelationManager>();
//已经从ab中load出具体资源
Dictionary<string, AssetResObj> loadObj = new Dictionary<string, AssetResObj>();//key是bundleName
//ab加载完成后的回调
Dictionary<string, LoadAssetBundleCallBackManager> loadBundleCallBack = new Dictionary<string, LoadAssetBundleCallBackManager>();
public static IABManager instance;
void Awake() {
instance = this;
StartCoroutine(IABManifestLoader.Instance.LoadManifeset());
}
//表示是否加载了AssetBundle
public bool IsLoadingAssetBundle(string bundleName) {
if (!loadHelper.ContainsKey(bundleName)){
return false;
} else {
return true;
}
}
#region 由下层提供API
public bool IsLoadFinish(string bundleName) {
return loadHelper.ContainsKey(bundleName);
}
public void RemoveBundle(string bundleName) {
if (loadHelper.ContainsKey(bundleName)) {
loadHelper.Remove(bundleName);
}
}
string GetBundlePath(string bundleName) {
string path = Path.Combine(IPathTools.GetAssetBundlePath(),bundleName);
path = IPathTools.StandardPath(path);
Debug.Log(path);
return path;
}
public void LoadSingleObject(string bundleName, string resName, LoadObjectCallBack callBack)
{
//表示 是否已经缓存了物体
if (loadObj.ContainsKey(bundleName))
{
AssetResObj tmpRes = loadObj[bundleName];
Object tmpObj = tmpRes.GetResObj(resName);
if (tmpObj != null) {
callBack(tmpObj);
return;
}
}
//表示bundle已经加载过
if (loadHelper.ContainsKey(bundleName))
{
LoadObjectFromBundle(bundleName, resName, callBack);
}
//加载bundle
else
{
StartCoroutine(LoadAssetBundle(bundleName, (tmpBundleName) => {
LoadObjectFromBundle(bundleName, resName, callBack);
}));
}
}
void LoadObjectFromBundle(string bundleName, string resName, LoadObjectCallBack callBack)
{
if (loadHelper.ContainsKey(bundleName))
{
IABRelationManager relation = loadHelper[bundleName];
Object tmpObj = relation.GetSingleResource(resName);
//把Object存缓存
AssetObj tmpAssetObj = new AssetObj(tmpObj);
if (!loadObj.ContainsKey(bundleName))
{
AssetResObj tmpRes = new AssetResObj(resName, tmpAssetObj);
loadObj.Add(bundleName, tmpRes);
}
else {
AssetResObj resObj = loadObj[bundleName];
resObj.AddResObj(resName, tmpAssetObj);
}
if (callBack != null)
{
callBack(tmpObj);
}
}
else {
if (callBack != null)
{
callBack(null);
}
}
}
IEnumerator LoadAssetBundleDependences(string bundleName, string refName)
{
if (!loadHelper.ContainsKey(bundleName))
{
yield return LoadAssetBundle(bundleName);
}
if (refName != null)
{
IABRelationManager loader = loadHelper[bundleName];
loader.AddRefference(refName);
}
}
public IEnumerator LoadAssetBundle(string bundleName, LoadAssetBundleCallBack callBack = null)
{
if (!IABManifestLoader.Instance.IsLoadFinish())
{
yield return null;
}
//管理ab加载完成后的回调函数
if (callBack != null) {
if (loadBundleCallBack.ContainsKey(bundleName))
{
LoadAssetBundleCallBackManager callBackManager = loadBundleCallBack[bundleName];
callBackManager.AddCallBack(callBack);
}
else {
LoadAssetBundleCallBackManager callBackManager = new LoadAssetBundleCallBackManager(bundleName);
callBackManager.AddCallBack(callBack);
loadBundleCallBack.Add(bundleName, callBackManager);
}
}
if (preLoadHelper.ContainsKey(bundleName))
{
yield return null;
}
else {
IABRelationManager relation = new IABRelationManager();
relation.Initial(bundleName);
preLoadHelper.Add(bundleName, relation);
string bundlePath = GetBundlePath(bundleName);
WWW www = new WWW(bundlePath);
yield return www;
Debug.Log("bundlePath " + bundlePath);
if (!string.IsNullOrEmpty(www.error))
{
Debug.Log(www.error);
preLoadHelper.Remove(bundleName);
}
else
{
AssetBundle ab = www.assetBundle;
string[] dependencies = IABManifestLoader.Instance.assetManifest.GetAllDependencies(ab.name);
IABRelationManager tmpRelation = preLoadHelper[ab.name];
tmpRelation.SetAssetBundle(ab);
tmpRelation.SetDependences(dependencies);
if (!loadHelper.ContainsKey(ab.name))
{
loadHelper.Add(ab.name, relation);
preLoadHelper.Remove(bundleName);
Debug.Log("abName " + ab.name);
}
//加载依赖
for (int i = 0; i < dependencies.Length; i++)
{
if (!loadHelper.ContainsKey(dependencies[i]))
{
yield return LoadAssetBundleDependences(dependencies[i], ab.name);
}
}
if (loadBundleCallBack.ContainsKey(ab.name)) {
loadBundleCallBack[ab.name].CallBack(ab.name);
}
}
www.Dispose();
}
}
#endregion
//对外接口
//释放一个bundle中的一个资源
public void DisposeResObj(string bundleName, string resName)
{
if (loadObj.ContainsKey(bundleName))
{
AssetResObj tmpObj = loadObj[bundleName];
tmpObj.ReleaseResObj(resName);
}
}
//释放整个bundle中的资源
public void DisposeResObj(string bundleName)
{
if (loadObj.ContainsKey(bundleName))
{
AssetResObj tmpObj = loadObj[bundleName];
tmpObj.ReleaseAllResObj();
Resources.UnloadUnusedAssets();
}
}
//释放所有的bundle加载出来的资源
public void DisposeAllObj()
{
List<string> keys = new List<string>();
keys.AddRange(loadObj.Keys);
for (int i = 0; i < loadObj.Count; i++)
{
DisposeResObj(keys[i]);
}
loadObj.Clear();
}
public void DisposeBundle(string bundleName)
{
if (loadHelper.ContainsKey(bundleName))
{
IABRelationManager loader = loadHelper[bundleName];
List<string> dependences = loader.GetDependences();
for (int i = 0; i < dependences.Count; i++)
{
if (loadHelper.ContainsKey(dependences[i]))
{
IABRelationManager dependence = loadHelper[dependences[i]];
if (dependence.RemoveReference(bundleName))
{
DisposeBundle(dependence.GetBundleName());
}
dependence.RemoveReference(bundleName);
}
}
if (loader.GetRefference().Count <= 0)
{
loader.Dispose();
loadHelper.Remove(bundleName);
}
}
}
public void DisposeAllBundle()
{
List<string> keys = new List<string>();
keys.AddRange(loadHelper.Keys);
for (int i = 0; i < loadHelper.Count; i++)
{
IABRelationManager loader = loadHelper[keys[i]];
loader.Dispose();
}
loadHelper.Clear();
}
public void DisposeAllBundleAndRes()
{
DisposeAllObj();
DisposeAllBundle();
}
}
IPathTools.cs
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Collections.Generic;
public class IPathTools {
public static string GetPlatformFolderName(RuntimePlatform platform) {
switch (platform) {
case RuntimePlatform.Android:
return "Android";
case RuntimePlatform.IPhonePlayer:
return "IOS";
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
return "windows";
case RuntimePlatform.OSXPlayer:
case RuntimePlatform.OSXEditor:
return "OSX";
default:
return null;
}
}
public static string GetAppFilePath() {
string tmpPath = "";
#if UNITY_ANDROID
tmpPath = "jar:file://" + Application.streamingAssetsPath;
#elif UNITY_IPHONE
tmpPath = Application.streamingAssetsPath;
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR
tmpPath = "file://" + Application.streamingAssetsPath;
#else
tmpPath = string.Empty;
#endif
return tmpPath;
}
public static string GetAssetBundlePath() {
string platFolder = GetPlatformFolderName(Application.platform);
string allPath = Path.Combine(GetAppFilePath(), platFolder);
allPath = StandardPath(allPath);
return allPath;
}
public static string GetEditeABOutPath() {
string tmpPath = "";
if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.OSXEditor)
{
tmpPath = Application.streamingAssetsPath;
}
else
{
tmpPath = Application.persistentDataPath;
}
return Path.Combine(tmpPath, GetPlatformFolderName(Application.platform));
}
public static string GetABManifestName() {
string name = GetPlatformFolderName(Application.platform) ;
string path = GetAssetBundlePath();
return StandardPath(Path.Combine(path, name));
}
public static string StandardPath(string oldPath) {
string newPath = oldPath;
if (oldPath.Contains("\\")) {
newPath = oldPath.Replace("\\","/");
}
return newPath;
}
}
TestLoad.cs
using UnityEngine;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.IO;
public class TestLoad : MonoBehaviour {
// Use this for initialization
public GameObject go;
public void Load() {
IABManager.instance.LoadSingleObject("load.ab", "Cube", (o) =>
{
if (o != null)
{
go = Instantiate(o, Vector3.zero, Quaternion.identity) as GameObject;
}
});
}
public void ChangeMaterial() {
MeshRenderer mr = go.GetComponent<MeshRenderer>();
IABManager.instance.LoadSingleObject("material.ab", "m_Material2", (o)=>{
Debug.Log("o"+o.name);
if (o != null)
{
Material m = o as Material;
mr.material = m;
}
});
}
public void DisposeBundle() {
IABManager.instance.DisposeBundle("load.ab");
}
}