赞
踩
在Unity开发过程中,经常需要对各类资源进行内存维护,eg:图片,音效,视频, Prefab 等。
下面给大家提供一个简单的AssetBundle管理方案:
- using Game.Utils;
- using LitJson;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using TMPro;
- using Unity.VisualScripting;
- using UnityEngine;
- using static UnityEditor.Progress;
-
- namespace Game.Load
- {
- public class BundleCatalog
- {
- public Dictionary<string, string> mPathMapping = new Dictionary<string, string>();
-
- public Dictionary<string, string[]> mDepensMapping = new Dictionary<string, string[]>();
-
- public Dictionary<string, string> bundleName2MD5 = new Dictionary<string, string>();
- }
-
- public class Reference
- {
- public int count;
-
- public float time;
-
- public void AddCount() { count++; }
-
- public void RemoveCount() { count--; }
-
- public void ResetTime() { time = 0; }
- }
-
- public class BundleLoader
- {
- public AssetBundleCreateRequest abRequest;
-
- public string path;
-
- public bool isDone = false;
-
- public int cacheCount;
-
- public List<string> cacheDepens;
-
- public List<Action<AssetBundle>> actions;
-
- public bool GetRequestIsDone()
- {
- if (isDone) return true;
- if (abRequest == null) return false;
- return abRequest.isDone;
- }
-
- public bool GetBundleIsDone()
- {
- if (!GetRequestIsDone()) return false;
- return cacheCount == cacheDepens.Count;
- }
- }
-
- public class BundleOperation
- {
- public BundleCatalog mBundleCalalog;
- // 记录已加载的AssetBundle引用计数
- private Dictionary<string, Reference> assetBundleReferenceCounts = new Dictionary<string, Reference>();
- // 记录已加载的AssetBundle
- private Dictionary<string, AssetBundle> loadedAssetBundles = new Dictionary<string, AssetBundle>();
- // 正在加载中的AssetBundle
- private Dictionary<string, BundleLoader> AssetBundlesLoader = new Dictionary<string, BundleLoader>();
- // 缓存时间
- private int mCacheTime = 3;
-
- public BundleOperation()
- {
- mBundleCalalog = JsonMapper.ToObject<BundleCatalog>(
- FileTools.GetFile(
- AssetUtils.GetRealPath(
- GameConst.GetAssetBundlePath(GameConst.Catalog)
- )
- )
- );
- }
-
- public string[] FindDepend(string assetBundlePath, List<string> mark = null)
- {
- if (mark == null)
- mark = new List<string>();
- assetBundlePath = GetPathByCatalog(assetBundlePath);
- if (mark.Contains(assetBundlePath))
- return default;
- else
- mark.Add(assetBundlePath);
- if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
- {
- foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
- {
- FindDepend(depend, mark);
- }
- }
- return mark.ToArray();
- }
-
- public void LoadBundleAsync(string assetBundlePath, Action<AssetBundle> action = null)
- {
- LoadBundleAsync(assetBundlePath, action, new List<string>());
- }
-
- private void LoadBundleAsync(string assetBundlePath, Action<AssetBundle> action = null, List<string> mark = null)
- {
- if (mark == null)
- mark = new List<string>();
- assetBundlePath = GetPathByCatalog(assetBundlePath);
- if (mark.Contains(assetBundlePath))
- return;
- else
- mark.Add(assetBundlePath);
-
- if (loadedAssetBundles.ContainsKey(assetBundlePath))
- {
- action?.Invoke(loadedAssetBundles[assetBundlePath]);
- return;
- }
- if (AssetBundlesLoader.ContainsKey(assetBundlePath))
- {
- AssetBundlesLoader[assetBundlePath].actions.Add(action);
- return;
- }
- if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
- {
- foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
- {
- LoadBundleAsync(depend, null, mark);
- }
- }
- AssetBundleCreateRequest ab = AssetBundle.LoadFromFileAsync(AssetUtils.GetRealPath(GameConst.GetAssetBundlePath(assetBundlePath)));
- AssetBundlesLoader.Add(assetBundlePath, new BundleLoader()
- {
- cacheDepens = mBundleCalalog.mDepensMapping[assetBundlePath].ToList(),
- isDone = false,
- path = assetBundlePath,
- abRequest = ab,
- actions = new List<Action<AssetBundle>> { action },
- cacheCount = 0
- });
- }
-
- public AssetBundle LoadBundleSync(string assetBundlePath)
- {
- return LoadBundleSync(assetBundlePath, new List<string>());
- }
-
- private AssetBundle LoadBundleSync(string assetBundlePath, List<string> mark = null)
- {
- if (mark == null)
- mark = new List<string>();
- assetBundlePath = GetPathByCatalog(assetBundlePath);
- if (mark.Contains(assetBundlePath))
- return default;
- else
- mark.Add(assetBundlePath);
- if (loadedAssetBundles.ContainsKey(assetBundlePath))
- {
- return loadedAssetBundles[assetBundlePath];
- }
- if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
- {
- foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
- {
- LoadBundleSync(depend, mark);
- }
- }
- AssetBundle ab = AssetBundle.LoadFromFile(
- AssetUtils.GetRealPath(
- GameConst.GetAssetBundlePath(assetBundlePath)
- )
- );
- loadedAssetBundles.Add(assetBundlePath, ab);
- return loadedAssetBundles[assetBundlePath];
- }
-
- public string GetPathByCatalog(string assetBundlePath)
- {
- foreach (var item in mBundleCalalog.mPathMapping)
- {
- if (item.Key.Contains(assetBundlePath))
- {
- return item.Value;
- }
- }
- return assetBundlePath;
- }
-
- public string GetPathByCatalogKey(string assetBundlePath)
- {
- foreach (var item in mBundleCalalog.mPathMapping)
- {
- if (item.Key.Contains(assetBundlePath))
- {
- return item.Key;
- }
- }
- return assetBundlePath;
- }
-
- private void UnloadAssetBundle(string assetBundlePath)
- {
- assetBundlePath = GetPathByCatalog(assetBundlePath);
- if (loadedAssetBundles.ContainsKey(assetBundlePath))
- {
- loadedAssetBundles[assetBundlePath].Unload(true);
- loadedAssetBundles.Remove(assetBundlePath);
- }
- }
-
- public void IncreaseAssetBundleReferenceCount(string assetBundlePath)
- {
- IncreaseAssetBundleReferenceCount(assetBundlePath, new List<string>());
- }
-
- private void IncreaseAssetBundleReferenceCount(string assetBundlePath, List<string> mark = null)
- {
- if (mark == null)
- mark = new List<string>();
- assetBundlePath = GetPathByCatalog(assetBundlePath);
- if (mark.Contains(assetBundlePath))
- return;
- else
- mark.Add(assetBundlePath);
- if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
- {
- foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
- {
- IncreaseAssetBundleReferenceCount(depend, mark);
- }
- }
- if (!assetBundleReferenceCounts.ContainsKey(assetBundlePath))
- {
- assetBundleReferenceCounts.Add(assetBundlePath, new Reference() { count = 0, time = 0 });
- }
- assetBundleReferenceCounts[assetBundlePath].AddCount();
- }
-
- public void DecreaseAssetBundleReferenceCount(string assetBundlePath)
- {
- DecreaseAssetBundleReferenceCount(assetBundlePath, new List<string>());
- }
-
- private void DecreaseAssetBundleReferenceCount(string assetBundlePath, List<string> mark = null)
- {
- if (mark == null)
- mark = new List<string>();
- assetBundlePath = GetPathByCatalog(assetBundlePath);
- if (mark.Contains(assetBundlePath))
- return;
- else
- mark.Add(assetBundlePath);
- if (mBundleCalalog.mDepensMapping.ContainsKey(assetBundlePath))
- {
- foreach (var depend in mBundleCalalog.mDepensMapping[assetBundlePath])
- {
- DecreaseAssetBundleReferenceCount(depend, mark);
- }
- }
- if (assetBundleReferenceCounts.ContainsKey(assetBundlePath))
- {
- assetBundleReferenceCounts[assetBundlePath].RemoveCount();
- if (assetBundleReferenceCounts[assetBundlePath].count < 0)
- {
- Log.Error("引用计数小于0:", assetBundlePath);
- }
- }
- else
- {
- Log.Error("引用不存在:", assetBundlePath);
- }
- }
-
- public string GetReferenceCount(string assetBundlePath)
- {
- assetBundlePath = GetPathByCatalog(assetBundlePath);
- if (assetBundleReferenceCounts.ContainsKey(assetBundlePath))
- {
- return "引用:" + assetBundleReferenceCounts[assetBundlePath].count.ToString();
- }
- return "引用:不存在";
- }
-
- public void OnTick()
- {
- UpdateReference();
- UpdateLoader();
- }
-
- public void UpdateLoader()
- {
- foreach (var item in AssetBundlesLoader)
- {
- if (item.Value.GetRequestIsDone() && !loadedAssetBundles.ContainsKey(item.Key))
- {
- foreach (var item2 in AssetBundlesLoader)
- {
- if (item2.Value.cacheDepens.Contains(item.Key))
- {
- item2.Value.cacheCount++;
- }
- }
- }
- }
- List<string> succKey = new List<string>();
- foreach (var item in AssetBundlesLoader)
- {
- if (item.Value.GetBundleIsDone())
- {
- succKey.Add(item.Key);
- }
- }
-
- foreach (var item in succKey)
- {
- loadedAssetBundles.Add(item, AssetBundlesLoader[item].abRequest.assetBundle);
- foreach (var action in AssetBundlesLoader[item].actions)
- {
- action?.Invoke(AssetBundlesLoader[item].abRequest.assetBundle);
- }
- AssetBundlesLoader.Remove(item);
- }
- }
-
- public void UpdateReference()
- {
- List<string> overtime = new List<string>();
- foreach (var item in assetBundleReferenceCounts)
- {
- if (item.Value.count <= 0)
- {
- item.Value.time += Time.deltaTime;
- if (item.Value.time > mCacheTime)
- {
- overtime.Add(item.Key);
- }
- }
- else
- {
- item.Value.ResetTime();
- }
- }
- foreach (var item in overtime)
- {
- assetBundleReferenceCounts.Remove(item);
- UnloadAssetBundle(item);
- }
- }
- }
- }
-
-
简单的说:
在外部调用 LoadBundleSync/LoadBundleAsync 后进行IncreaseAssetBundleReferenceCount
在Destroy时进行DecreaseAssetBundleReferenceCount
OnTick 刷新检测异步加载 以及释放缓存
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。