1.生成Asset Bundle
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
public class BuildAssetBundle : Editor{
[MenuItem("Tools/BuildAssetBundle")]
public static void BuildBundle()
{
string abPath = Path.Combine(Application.streamingAssetsPath,"AssetBundle");
if (!Directory.Exists(abPath))
{
Directory.CreateDirectory(abPath);
}
BuildPipeline.BuildAssetBundles(abPath, BuildAssetBundleOptions.ChunkBasedCompression,EditorUserBuildSettings.activeBuildTarget);
AssetDatabase.Refresh();
}
[MenuItem("Tools/CreatScriptTableAsset")]
public static void CreatScriptTableAsset()
{
ScriptTableTest test = ScriptableObject.CreateInstance<ScriptTableTest>();
AssetDatabase.CreateAsset(test, "Assets/Resources/ScriptTableTest.asset");
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
2.AssetBundleManager 管理(资源加载和卸载)
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public enum ABLoadStateEnum
{
None,
Loading,
Loaded,
Release
}
public enum AssetLoadStateEnum
{
LoadFail,
Loading,
Loaded
}
public class AssetBundleManager : MonoBehaviour {
private static AssetBundleManager instance;
public static AssetBundleManager Instance
{
get
{
return instance;
}
}
private Coroutine mRequestABCor;
private string mAssetBundlePath;
private Dictionary<string, AssetBundleBaseInfo> mABBaseInfoDic = new Dictionary<string, AssetBundleBaseInfo>();
public delegate void AssetReqCallBack(UnityEngine.Object obj, string assetName, string assetBundelName);
private Queue<AssetReq> mAssetReqQueue = new Queue<AssetReq>();
private List<AssetReq> mAssetReqs = new List<AssetReq>();
private List<AssetReq> mLoadingAssetReqs = new List<AssetReq>();
private Dictionary<string, AssetInfo> mLoadedAssetInfoDic = new Dictionary<string, AssetInfo>();
private Dictionary<string, string> mAssetNameToABNameDic = new Dictionary<string, string>();
private Dictionary<string, AssetBundleCreateRequest> mAbNameToCreateQequestDic = new Dictionary<string, AssetBundleCreateRequest>();
private int mMaxLoadAssetReqCount = 5;
private List<string> mDelayReleaseABNames = new List<string>();
private List<bool> mLoadingAssetFlags = new List<bool>();
private int mMaxReleaseAssetCount = 20;
private float mTimeInterval = 50;
private float mTimer;
private void Awake()
{
instance = this;
for (int i = 0; i < mMaxLoadAssetReqCount; i++)
{
mLoadingAssetFlags.Add(false);
}
}
#region 获取所有资源依赖
private void Start()
{
mAssetBundlePath = Path.Combine(Application.streamingAssetsPath, "AssetBundle/AssetBundle");
if (mRequestABCor != null)
{
StopCoroutine(mRequestABCor);
mRequestABCor = null;
}
mRequestABCor = StartCoroutine(RequestAssetBundle(0));
}
public IEnumerator RequestAssetBundle(int version)
{
AssetBundleCreateRequest abCreateRequest = AssetBundle.LoadFromFileAsync(mAssetBundlePath);
yield return abCreateRequest;
if (abCreateRequest.isDone)
{
if (abCreateRequest.assetBundle != null)
{
AssetBundleRequest abRequest = abCreateRequest.assetBundle.LoadAllAssetsAsync();
yield return abRequest;
if (abRequest.isDone)
{
AssetBundleManifest abMainfest = abRequest.asset as AssetBundleManifest;
if (abMainfest != null)
{
string[] allABNames = abMainfest.GetAllAssetBundles();
for (int i = 0; i < allABNames.Length; i++)
{
string abName = allABNames[i];
string[] allDependence = abMainfest.GetAllDependencies(abName);
AssetBundleBaseInfo abBaseInfo = new AssetBundleBaseInfo(abName, allDependence, version);
mABBaseInfoDic.Add(abName, abBaseInfo);
}
}
}
}
}
}
#endregion
#region 加载资源
public void LoadAsset<T>(string assetName, string assetBundleName, AssetReqCallBack callBack) where T:UnityEngine.Object
{
if (mLoadedAssetInfoDic.ContainsKey(assetName))
{
callBack(mLoadedAssetInfoDic[assetName].assetObj, assetName, assetBundleName);
}
else
{
AssetReq assetReq = new AssetReq(assetName, assetBundleName, callBack, false);
mAssetReqQueue.Enqueue(assetReq);
AddAssetReqToList();
StartLoadAsset<T>();
}
}
private void AddAssetReqToList()
{
mLoadingAssetReqs.Clear();
for (int i = 0; i < mMaxLoadAssetReqCount; i++)
{
if (mAssetReqQueue.Count <= 0)
{
break;
}
else
{
AssetReq assetReq = mAssetReqQueue.Dequeue();
if (assetReq != null)
{
mLoadingAssetReqs.Add(assetReq);
}
}
}
}
private void StartLoadAsset<T>() where T:UnityEngine.Object
{
for (int i = 0; i < mLoadingAssetReqs.Count; i++)
{
AssetReq assetReq = mLoadingAssetReqs[i];
if (assetReq != null)
{
StartCoroutine(LoadAssetCor<T>(assetReq, assetReq.assetBundleName, i));
}
}
}
private IEnumerator LoadAssetCor<T>(AssetReq assetReq, string abName, int curIndex) where T:UnityEngine.Object
{
if (assetReq == null)
{
if (!CheckIsHaveAssetBundle(abName))
{
yield break;
}
AssetBundleBaseInfo abBaseInfo = mABBaseInfoDic[abName];
if (abBaseInfo.abLoadState == ABLoadStateEnum.Loaded)
{
yield break;
}
while (abBaseInfo.abLoadState == ABLoadStateEnum.Loading)
{
yield return null;
}
abBaseInfo.abLoadState = ABLoadStateEnum.Loading;
string abPath = Application.streamingAssetsPath + "/AssetBundle/" + abBaseInfo.assetBundleName;
AssetBundleCreateRequest abCreateRequest = AssetBundle.LoadFromFileAsync(abPath);
yield return abCreateRequest;
if (abCreateRequest.isDone)
{
abBaseInfo.abLoadState = ABLoadStateEnum.Loaded;
abBaseInfo.refCount++;
}
}
else
{
if (!CheckIsHaveAssetBundle(abName))
{
yield break;
}
AssetBundleBaseInfo abBaseInfo = mABBaseInfoDic[abName];
while (abBaseInfo.abLoadState == ABLoadStateEnum.Loading)
{
yield return null;
}
if (abBaseInfo.abLoadState == ABLoadStateEnum.None)
{
abBaseInfo.abLoadState = ABLoadStateEnum.Loading;
}
if (mDelayReleaseABNames.Contains(assetReq.assetBundleName))
{
mDelayReleaseABNames.Remove(assetReq.assetBundleName);
}
for (int i = 0; i < abBaseInfo.dependceArr.Length; i++)
{
string assetBundlename = abBaseInfo.dependceArr[i];
StartCoroutine(LoadAssetCor<T>(null, assetBundlename,-1));
}
AssetBundleCreateRequest abCreateRequest = null;
string abPath = Application.streamingAssetsPath + "/AssetBundle/" + abBaseInfo.assetBundleName;
if (mAbNameToCreateQequestDic.ContainsKey(abName))
{
abCreateRequest = mAbNameToCreateQequestDic[abName];
}
else
{
abCreateRequest = AssetBundle.LoadFromFileAsync(abPath);
yield return abCreateRequest;
}
if (abCreateRequest.isDone)
{
abBaseInfo.abLoadState = ABLoadStateEnum.Loaded;
abBaseInfo.assetBundle = abCreateRequest.assetBundle;
if (!mAbNameToCreateQequestDic.ContainsKey(abName))
{
mAbNameToCreateQequestDic.Add(abName, abCreateRequest);
}
}
if (abBaseInfo.abLoadState == ABLoadStateEnum.Loaded)
{
if (!abBaseInfo.assetInfoDic.ContainsKey(assetReq.assetBundleName))
{
AssetInfo assetInfo = new AssetInfo(assetReq.assetName,null, AssetLoadStateEnum.Loading);
Dictionary<string, AssetInfo> dic = new Dictionary<string, AssetInfo>();
dic.Add(assetReq.assetName, assetInfo);
abBaseInfo.assetInfoDic.Add(assetReq.assetBundleName, dic);
AssetBundleRequest abRequest = abBaseInfo.assetBundle.LoadAssetAsync<T>(assetReq.assetName);
yield return abRequest;
if (abRequest.isDone)
{
assetInfo.assetObj = abRequest.asset;
string assetName = abRequest.asset.name;
if (!mLoadedAssetInfoDic.ContainsKey(assetName))
{
mLoadedAssetInfoDic.Add(assetName, assetInfo);
}
if (!mAssetNameToABNameDic.ContainsKey(assetName))
{
mAssetNameToABNameDic.Add(assetName,abName);
}
}
}
else
{
AssetInfo assetInfo = new AssetInfo(assetReq.assetName, null, AssetLoadStateEnum.Loading);
if (!abBaseInfo.assetInfoDic.ContainsKey(assetReq.assetBundleName))
{
Dictionary<string, AssetInfo> dic = new Dictionary<string, AssetInfo>();
dic.Add(assetReq.assetName, assetInfo);
abBaseInfo.assetInfoDic.Add(assetReq.assetBundleName, dic);
}
else
{
if (!abBaseInfo.assetInfoDic[assetReq.assetBundleName].ContainsKey(assetReq.assetName))
{
abBaseInfo.assetInfoDic[assetReq.assetBundleName].Add(assetReq.assetName, assetInfo);
}
}
AssetBundleRequest abRequest = abBaseInfo.assetBundle.LoadAssetAsync<T>(assetReq.assetName);
yield return abRequest;
if (abRequest.isDone)
{
assetInfo.assetObj = abRequest.asset;
string assetName = abRequest.asset.name;
if (!mLoadedAssetInfoDic.ContainsKey(assetName))
{
mLoadedAssetInfoDic.Add(assetName, assetInfo);
}
if (!mAssetNameToABNameDic.ContainsKey(assetName))
{
mAssetNameToABNameDic.Add(assetName, abName);
}
}
}
UnityEngine.Object assetObj = abBaseInfo.assetInfoDic[assetReq.assetBundleName][assetReq.assetName].assetObj;
assetReq.assetReqCallBack(assetObj, assetReq.assetName, abBaseInfo.assetBundleName);
}
abBaseInfo.refCount++;
mLoadingAssetFlags[curIndex] = false;
yield return new WaitForEndOfFrame();
if (!mLoadingAssetFlags.Contains(true))
{
if (mAssetReqQueue.Count > 0)
{
AddAssetReqToList();
StartLoadAsset<T>();
}
}
}
}
private bool CheckIsHaveAssetBundle(string abName)
{
return mABBaseInfoDic.ContainsKey(abName);
}
#endregion
#region 释放资源
public void ReleaseAsset(string abName,bool isDelayRelease, AssetReqCallBack callBack)
{
if (mABBaseInfoDic.ContainsKey(abName))
{
AssetBundleBaseInfo abBaseInfo = mABBaseInfoDic[abName];
abBaseInfo.refCount--;
if (abBaseInfo.refCount < 0)
{
abBaseInfo.refCount = 0;
}
if (isDelayRelease)
{
mDelayReleaseABNames.Add(abName);
}
else
{
if (abBaseInfo.abLoadState == ABLoadStateEnum.Loaded && abBaseInfo.assetBundle != null && abBaseInfo.refCount == 0)
{
UnLoadAssetBundle(abName);
}
}
if (callBack != null)
{
callBack(null,null,abName);
}
}
}
private void UnLoadAssetBundle(string abName)
{
AssetBundleBaseInfo abBaseInfo = mABBaseInfoDic[abName];
if (abBaseInfo != null)
{
abBaseInfo.assetInfoDic.Clear();
abBaseInfo.assetBundle.Unload(true);
abBaseInfo.abLoadState = ABLoadStateEnum.None;
abBaseInfo.assetBundle = null;
if (mAbNameToCreateQequestDic.ContainsKey(abName))
{
mAbNameToCreateQequestDic.Remove(abName);
}
foreach (var item in mAssetNameToABNameDic.Keys)
{
if (mAssetNameToABNameDic[item].Equals(abName))
{
Debug.Log("UnLoadAssetBundle.assetName " + item + " abName " + abName);
mLoadedAssetInfoDic.Remove(item);
}
}
Debug.Log("UnLoadAssetBundle.abName " + abName);
}
}
private void DelayReleaseAsset()
{
if (mDelayReleaseABNames.Count > mMaxReleaseAssetCount)
{
int removeIndex = 0;
for (int i = 0; i < mDelayReleaseABNames.Count; i++)
{
string abName = mDelayReleaseABNames[i];
UnLoadAssetBundle(abName);
removeIndex++;
}
mDelayReleaseABNames.RemoveRange(0, removeIndex);
}
}
private void Update()
{
if (mTimer >= mTimeInterval)
{
DelayReleaseAsset();
}
else
{
mTimer += Time.deltaTime;
}
}
#endregion
public class AssetBundleBaseInfo
{
public string assetBundleName;
public string[] dependceArr;
public int refCount;
public int version;
public AssetBundle assetBundle;
public ABLoadStateEnum abLoadState;
public Dictionary<string, Dictionary<string, AssetInfo>> assetInfoDic = new Dictionary<string, Dictionary<string, AssetInfo>>();
public AssetBundleBaseInfo(string abName, string[] dependences, int version)
{
assetBundleName = abName;
dependceArr = dependences;
this.version = version;
}
}
public class AssetInfo
{
public UnityEngine.Object assetObj;
public string assetName;
public AssetLoadStateEnum assetLoadStateEnum;
public AssetInfo(string assetName, UnityEngine.Object asset, AssetLoadStateEnum state)
{
assetObj = asset;
assetLoadStateEnum = state;
}
}
public class AssetReq
{
public string assetName;
public string assetBundleName;
public AssetReqCallBack assetReqCallBack;
public bool isDelay;
public AssetReq(string assetName, string abName, AssetReqCallBack callBack, bool isDelay)
{
this.assetName = assetName;
assetBundleName = abName;
assetReqCallBack = callBack;
this.isDelay = isDelay;
}
}
}
3.加载资源
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Main : MonoBehaviour {
public Button loadAssetBtn;
public Button releaseAssetBtn;
public Button loadBgBtn;
public Button releaseBgBtn;
public Button loadScriptTabelBtn;
public Button releasecriptTabelBtn;
public Image nameImg;
public Image bgImg;
public Text scriptTabel_text;
private void Start()
{
loadAssetBtn.onClick.AddListener(LoadImg);
releaseAssetBtn.onClick.AddListener(ReleaseImg);
loadBgBtn.onClick.AddListener(LoadBg);
releaseBgBtn.onClick.AddListener(ReleaseBg);
loadScriptTabelBtn.onClick.AddListener(LoadScriptTable);
releasecriptTabelBtn.onClick.AddListener(ReleaseScriptTable);
}
private void LoadCube()
{
AssetBundleManager.Instance.LoadAsset<GameObject>("Cube","prefab/cube",(obj,assetName,assetBundleName)=>
{
GameObject go = Instantiate(obj) as GameObject;
});
}
private void ReleaseCube()
{
AssetBundleManager.Instance.ReleaseAsset("prefab/cube",false,null);
}
private void LoadImg()
{
AssetBundleManager.Instance.LoadAsset<Sprite>("wy_bg_19", "ui/common",(obj, assetName, assetBundleName) =>
{
Sprite sprite = (Sprite)obj;
nameImg.sprite = sprite;
});
}
private void ReleaseImg()
{
AssetBundleManager.Instance.ReleaseAsset("ui/common", false, null);
}
private void LoadBg()
{
AssetBundleManager.Instance.LoadAsset<Sprite>("drawCardBg1", "ui/common", (obj, assetName, assetBundleName) =>
{
Sprite sprite = (Sprite)obj;
bgImg.sprite = sprite;
});
}
private void ReleaseBg()
{
AssetBundleManager.Instance.ReleaseAsset("ui/common", false, null);
}
private void LoadScriptTable()
{
AssetBundleManager.Instance.LoadAsset<ScriptableObject>("ScriptTableTest", "scripttable/scripttabletest", (obj, assetName, assetBundleName) =>
{
ScriptTableTest scriptTabel = (ScriptTableTest)obj;
Debug.Log("LoadScriptTable.scriptTabel " + scriptTabel);
scriptTabel_text.text = scriptTabel.ID + "---" + scriptTabel.name;
});
}
private void ReleaseScriptTable()
{
AssetBundleManager.Instance.ReleaseAsset("scripttable/scrpttabletest", false, null);
}
}