【学习资料整理】Addressables资源管理器

本文介绍了如何使用单例模式创建一个资源管理器,管理Addressables加载的异步操作,包括使用字典存储资源句柄、模拟引用计数的AddressableInfo类,以及提供加载、释放和清除资源的API接口,适用于Unity游戏开发。
摘要由CSDN通过智能技术生成

编写管理器,封装资源的加载和卸载等功能,因为管理器唯一,所以采用单例模式开发。
简单写一个饿汉单例(可优化)

public class Singlenton<T> where T : new ()
{
    private static T _instance;

    public static T Instance
    {
        get
        {
            if (_instance == null) { _instance = new T(); };
            return _instance;
        }

    }
    protected Singlenton() { Init(); }

    protected virtual void Init() { }

}

Init函数提供给继承的管理器去做一些初始化操作,protected 的构造函数防止外部去声明对象,破坏唯一性

【主要内容】

由于Addressables加载的资源返回的是一个泛型句柄,AsyncOperationHandle,故可以声明一个为他的接口IEnumerator类型的字典,存储所有的句柄,采用字典类型,key为资源名和资源类型,即为

    //字典容器,存储异步加载返回的句柄
    private Dictionary<string, IEnumerator> HandleDic;
     protected override void Init()
    {
        HandleDic = new Dictionary<string, IEnumerator>();
    }

但普通类型的句柄,即AsyncOperationHandle提供了 public AsyncOperationHandle Convert();转为泛型类型的句柄,所以可以将IEnumerator改为AsyncOperationHandle,又由于有引用计数的需求,我们需要模拟构造一个类似引用计数的变量,所以声明类AddressableInfo,并提供两个成员变量

public class AddressableInfo {

    public AsyncOperationHandle handle;
    public uint Count;
    public AddressableInfo(AsyncOperationHandle handle)
    {
        this.handle = handle;
        Count += 1;
    }
}

同时更改字典类型为AddressableInfo

//字典容器,存储异步加载返回的句柄
private Dictionary<string, AddressableInfo> HandleDic;

    protected override void Init()
    {
        HandleDic = new Dictionary<string, AddressableInfo>();
    }

为是否屏蔽引用计数,提供一个引用计数模式的枚举,用于规范卸载指定资源的模式

//指定释放模式,once采用引用计数模式, Complete屏蔽该模式
public enum AddressableReleaseType
{
    Once,
    Complete
}

【提供API】

从基本需求考虑,需要一个加载指定资源函数,一个释放指定资源函数,一个清空函数,即LoadAssetasync(),Release(),Clear(),

//第二个参数传一个委托函数,可以添加实例化资源等等
    public void LoadAssetasync<T>(string name,Action<AsyncOperationHandle<T>> callBack)
    {
        //资源名拼接资源类型作为唯一Key
        string keyName = name + "_" + typeof(T).Name;


        if (HandleDic.ContainsKey(keyName))
        {
            var handle=HandleDic[keyName].handle.Convert<T>();
            //引用计数加1
            HandleDic[keyName].Count += 1;
            //如果资源加载完成,则执行回调
            if (handle.IsDone)
            {
                callBack(handle);
            }
            else
            {
                //如果这个时候 还没有异步加载完成 则添加委托 当完成时执行回调
                handle.Completed += (obj) => {
                    if (obj.Status == AsyncOperationStatus.Succeeded)
                        callBack(obj);
                };
            }
            return;
        }
        //第一次加载资源时,字典还没有对应句柄
        var Handle= Addressables.LoadAssetAsync<T>(name);
        Handle.Completed +=(obj)=> {
             //资源加载成功时,指定回调
            if (obj.Status.Equals(AsyncOperationStatus.Succeeded))
            {
                callBack(obj);
            }
            else
            {
                Debug.LogWarning(keyName + "资源加载失败");
                if (HandleDic.ContainsKey(keyName))
                    HandleDic.Remove(keyName);
            }


        };
        AddressableInfo info = new AddressableInfo(Handle);
        //第一次添加对应句柄的键值对
        HandleDic.Add(keyName, info);

    }

    //释放资源的方法, 参数2为是否启用引用计数,默认启用
    public void Release<T>(string name,AddressableReleaseType type = AddressableReleaseType.Once)
    {
        string keyName = name + "_" + typeof(T).Name;

        if (HandleDic.ContainsKey(keyName))
        {     
            //如果是使用引用计数,则仅当引用计数为0时,释放资源    
            if (type.Equals(AddressableReleaseType.Once)) { 
                HandleDic[keyName].Count -= 1;
                if (HandleDic[keyName].Count >0) return;           
            }
            HandleDic[keyName].Count = 0;
            AsyncOperationHandle<T> handle = HandleDic[keyName].handle.Convert<T>();
            Addressables.Release(handle);
            HandleDic.Remove(keyName);
        }


    }

    //清空资源
    public void Clear()
    {
        foreach (var item in HandleDic.Values)
        {
            Addressables.Release(item.handle);
        }
        HandleDic.Clear();
        AssetBundle.UnloadAllAssetBundles(true);
        Resources.UnloadUnusedAssets();
        GC.Collect();
    }

诸此类推,可以增加多资源加载和卸载api,例如想使用资源名加标签名引用多个资源
基本思路和上述API相同,故不再做多解释,加载模式的局别请自行了解

 //指定加载多个资源,指定模式加载
    public void LoadAssetasync<T>(Addressables.MergeMode mode, Action<T> callback,params string[] keys)
    {
        //List
        List<string> list = new List<string>(keys);
        string keyname = "";
        foreach (var item in list)
        {
            keyname += item + "_";
        }
        keyname +=  typeof(T).Name;

        AsyncOperationHandle<IList<T>> handle;
        if (HandleDic.ContainsKey(keyname)) {
            handle = HandleDic[keyname].handle.Convert<IList<T>>();
            HandleDic[keyname].Count +=1;
            if (handle.IsDone)
            {
                foreach (var item in handle.Result)
                {
                    callback(item);
                }
            }
            else
            {
                handle.Completed += (obj) => { 
                    if(obj.Status== AsyncOperationStatus.Succeeded)
                    {
                        foreach (var item in handle.Result)
                        {
                            callback(item);
                        }
                    }
                };
            }
            return;
        }

        handle = Addressables.LoadAssetsAsync<T>(list, callback, mode);
        handle.Completed += (obj) =>
        {
            if (obj.Status.Equals(AsyncOperationStatus.Failed))
            {
                Debug.LogWarning(keyname + "资源加载失败");
                if (HandleDic.ContainsKey(keyname))
                    HandleDic.Remove(keyname);
            }
        };
        AddressableInfo info = new AddressableInfo(handle);
        HandleDic.Add(keyname, info);
    }

    //释放多个资源的方法  
    public void Release<T>(AddressableReleaseType type = AddressableReleaseType.Once,params string[] keys)
    {
        //List
        List<string> list = new List<string>(keys);
        string keyname = "";
        foreach (var item in list)
        {
            keyname += item + "_";
        }
        keyname += typeof(T).Name;

        if (HandleDic.ContainsKey(keyname))
        {
            if (type.Equals(AddressableReleaseType.Once))
            {
                HandleDic[keyname].Count -= 1;
                if (HandleDic[keyname].Count > 0) return;
            }
            HandleDic[keyname].Count = 0;
            AsyncOperationHandle<T> handle = HandleDic[keyname].handle.Convert<T>();
            Addressables.Release(handle);
            HandleDic.Remove(keyname);
        }
    }

菜鸡整理的学习资料,如有不足,请大佬多指教

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值