思路很简单,传入图集名和资源名,利用Addressables提供的异步加载方式从ab包中加载。加载完成后存储进缓存字典里,以供后续使用。
添加引用计数,防止多个地方使用同一图集时,不会提前释放
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.U2D.SpriteAtlas;
using System.Collections.Generic;public class SpriteAtlasManager : MonoBehaviour
{// 单例实例private static SpriteAtlasManager _instance;public static SpriteAtlasManager Instance{get{if (_instance == null){GameObject go = new GameObject("SpriteAtlasManager");_instance = go.AddComponent<SpriteAtlasManager>();DontDestroyOnLoad(go);}return _instance;}}// 图集缓存字典private Dictionary<string, AtlasCacheInfo> _atlasCache = new Dictionary<string, AtlasCacheInfo>();/// <summary>/// 加载Sprite/// </summary>/// <param name="atlasName">图集的Addressable名称</param>/// <param name="spriteName">Sprite在图集中的名称</param>/// <param name="onComplete">加载完成回调</param>public void LoadSprite(string atlasName, string spriteName, System.Action<Sprite> onComplete){// 如果图集已加载if (_atlasCache.TryGetValue(atlasName, out AtlasCacheInfo cacheInfo)){// 直接获取SpriteSprite sprite = cacheInfo.Atlas.GetSprite(spriteName);if (sprite != null){cacheInfo.RefCount++; // 增加引用计数onComplete?.Invoke(sprite);}else{Debug.LogError($"图集 {atlasName} 中找不到Sprite: {spriteName}");onComplete?.Invoke(null);}return;}// 异步加载图集AsyncOperationHandle<SpriteAtlas> handle = Addressables.LoadAssetAsync<SpriteAtlas>(atlasName);handle.Completed += op =>{if (op.Status == AsyncOperationStatus.Succeeded){// 缓存图集var newCache = new AtlasCacheInfo{Handle = handle,Atlas = op.Result,RefCount = 1};_atlasCache.Add(atlasName, newCache);// 获取SpriteSprite sprite = newCache.Atlas.GetSprite(spriteName);if (sprite != null){onComplete?.Invoke(sprite);}else{Debug.LogError($"图集 {atlasName} 中找不到Sprite: {spriteName}");Addressables.Release(handle); // 立即释放_atlasCache.Remove(atlasName);onComplete?.Invoke(null);}}else{Debug.LogError($"图集 {atlasName} 加载失败");onComplete?.Invoke(null);}};}/// <summary>/// 释放Sprite/// </summary>/// <param name="atlasName">图集的Addressable名称</param>public void UnloadSprite(string atlasName){if (_atlasCache.TryGetValue(atlasName, out AtlasCacheInfo cacheInfo)){cacheInfo.RefCount--;if (cacheInfo.RefCount <= 0){Addressables.Release(cacheInfo.Handle);_atlasCache.Remove(atlasName);}}}// 图集缓存信息private class AtlasCacheInfo{public AsyncOperationHandle<SpriteAtlas> Handle;public SpriteAtlas Atlas;public int RefCount; // 引用计数}void OnDestroy(){// 清理所有缓存foreach (var pair in _atlasCache){Addressables.Release(pair.Value.Handle);}_atlasCache.Clear();}
}
使用例:
// 在需要加载Sprite的地方调用
SpriteAtlasManager.Instance.LoadSprite("UI_Atlas", "hero_icon", sprite =>
{if (sprite != null){GetComponent<Image>().sprite = sprite;}
});// 当不再需要时释放
SpriteAtlasManager.Instance.UnloadSprite("UI_Atlas");