当前位置: 首页 > news >正文

【Framework系列之Client】LoadManager、ResourceManager介绍

        今天来详细介绍一下LoadManager、ResourceManager。LoadManager和ResourceManager主要负责框架的资源加载和管理,话不多说直接开始。

LoadManager

        LoadManager主要的功能有:

  1. 提供资源加载的接口
  2. 提供资源卸载的接口
  3. 持有、管理AsyncOperationHandle句柄对象
  4. Loader类的创建于调用

        LoadManager定义了多种加载方式的接口。加载单个资源、加载多个资源、加载场景。接口参数由资源名称、加载回调方法组成。代码如下:

/// <summary>异步加载资源(单个)</summary>
/// <param name="pAssetName">资源名称</param>
/// <param name="pLoadCallback">加载回调</param>
public void LoadAssetAsync(string pAssetName, Action<bool> pLoadCallback = null)
{
    LoadAsset(pAssetName, ELoadType.LoadAssetAsync, pLoadCallback);
}

/// <summary>异步加载资源(多个)</summary>
/// <param name="pLabelsName">Labals</param>
/// <param name="pLoadCallback">加载回调</param>
public void LoadAssetsAsyc(string pLabelsName, Action<bool> pLoadCallback = null)
{
    LoadAsset(pLabelsName, ELoadType.LoadAssetsAsyc, pLoadCallback);
}

/// <summary>加载场景</summary>
/// <param name="pSceneName"></param>
/// <param name="pLoadCallback"></param>
public void LoadSceneAsyc(string pSceneName, Action<bool> pLoadCallback = null)
{
    LoadAsset(pSceneName, ELoadType.LoadSceneAsyc, pLoadCallback);
}

        不同的加载接口最终统一调用LoadAsset方法。LoadAsset负责Loader的创建与加载接口的调用。LoadAsset内通过调用Loader的加载接口进行资源加载。创建出来的Loader会被进行缓存,在加载完成后会移除对应的Loader。这样做的目的是避免同一资源重复。

        为避免资源的重复加载,AsyncOperationHandle句柄会被保存在成员对象mHandleDictionay中,根据资源名称的HashCode来进行判断。如果已经加载过,则直接返回。

private Dictionary<int, AsyncOperationHandle> mHandleDictionay = new Dictionary<int, AsyncOperationHandle>();
private Dictionary<int, Loader> mLoaderDictionary = new Dictionary<int, Loader>();

private void LoadAsset(string pAssetName, ELoadType pLoadType, Action<bool> pLoadCallback = null)
{
    int loaderId = pAssetName.GetHashCode();
    if (mHandleDictionay.ContainsKey(loaderId))
    {
        pLoadCallback?.Invoke(true);
        return;
    }

    Loader loader = CreateLoader(loaderId, pLoadCallback);
    if (loader != null)
    {
        switch (pLoadType)
        {
            case ELoadType.LoadAssetAsync:
                loader.LoadAssetAsync(pAssetName);
                break;

            case ELoadType.LoadAssetsAsyc:
                loader.LoadAssetsAsync(pAssetName);
                break;

            case ELoadType.LoadSceneAsyc:
                loader.LoadSceneAsync(pAssetName);
                break;
        }
    }
}

private Loader CreateLoader(int loaderId, Action<bool> pLoadCallback = null)
{
    Loader loader = null;
    if (!mLoaderDictionary.ContainsKey(loaderId))
    {
        loader = new Loader(loaderId, pLoadCallback);
        mLoaderDictionary.Add(loaderId, loader);
    }
    return loader;
}

        接下来说一下Loader类。Loader类的主要功能有:

  1. 提供资源加载的接口。
  2. 负责Addressables资源加载接口的调用。
  3. 持有LoaderId、mLoadCallback(加载回调)、mAsyncOperationHandle(加载句柄)这些成员变量。
  4. 完成加载后的处理。

        Loader类提供了多种对应Addressables加载资源的接口,加载单个资源、加载多个资源、加载场景。这些接口实现了Addressables对资源加载的调用。

        资源加载完成后统一回调LoadComplete方法,LoadComplete会传入AsyncOperationHandle参数。加载成功后会在LoadManager移除Loader,在LoadManager添加AsyncOperationHandle,在ResourceManager添加资源等操作。

private class Loader
{
    private int mLoaderId = -1;
    private Action<bool> mLoadCallback = null;
    private AsyncOperationHandle mAsyncOperationHandle = default;

    public Loader(int loaderId, Action<bool> pLoadCallback = null)
    {
        mLoaderId = loaderId;
        mLoadCallback = pLoadCallback;
    }

    #region AsyncOperationHandle.Completed
    public void LoadAssetAsync(string pAssetName)
    {
        mAsyncOperationHandle = Addressables.LoadAssetAsync<UnityEngine.Object>(pAssetName);
        mAsyncOperationHandle.Completed += LoadComplete;
    }

    public void LoadAssetsAsync(string pLabelsKey)
    {
        mAsyncOperationHandle = Addressables.LoadAssetsAsync<UnityEngine.Object>(pLabelsKey, null);
        mAsyncOperationHandle.Completed += LoadComplete;
    }

    public void LoadSceneAsync(string pSceneName)
    {
        mAsyncOperationHandle = Addressables.LoadSceneAsync(pSceneName);
        mAsyncOperationHandle.Completed += LoadComplete;
    }
    #endregion

    private void LoadComplete(AsyncOperationHandle pHandle)
    {
        if (pHandle.Status == AsyncOperationStatus.Succeeded)
        {
            ManagerCollection.LoadManager.RemoveLoader(mLoaderId);
            ManagerCollection.LoadManager.AddHandle(mLoaderId, pHandle);
            ManagerCollection.ResourceManager.AddAsset(pHandle.Result);
            mLoadCallback?.Invoke(true);
        }
        else if (pHandle.Status == AsyncOperationStatus.Failed)
        {
            Debug.LogWarning(pHandle.OperationException.Message);
            mLoadCallback?.Invoke(false);
        }
    }
}

        这里只展示了LoadManager的部分代码,关于完整代码,各位同学可以在文章最后获取Git下载工程。

ResourceManager

        ResourceManager主要功能有:

  1. 持有、管理各类型资源(类型包括:AudioClip、GameObject、TextAsset、Texture等等)。
  2. 提供各类型资源获取的接口。
  3. 提供添加资源的接口。
  4. 提供移除资源的接口。

        ResourceManager内定义了多个用于存储不同类型的Dictionary。

public class ResourceManager : ManagerBase<ResourceManager>
{
    private Dictionary<string, AudioClip> mAudioClipDictionary = new Dictionary<string, AudioClip>();
    private Dictionary<string, GameObject> mGameObjectDictionary = new Dictionary<string, GameObject>();
    private Dictionary<string, TextAsset> mTextAssetDictionary = new Dictionary<string, TextAsset>();
    public Dictionary<string, Texture> mTextureDictionary = new Dictionary<string, Texture>();
    private Dictionary<string, Sprite> mSpriteDictionary = new Dictionary<string, Sprite>();
}

        在LoadManager中提到过,加载成功后会调用ResourceManager的AddAsset方法进行资源的添加。AddAsset会根据资源类型,调用不同的添加方法,将资源保存到对应的Dictionary中。代码如下:

public void AddAsset(object pResult)
{
    if (pResult is List<UnityEngine.Object>)
    {
        List<UnityEngine.Object> assetList = pResult as List<UnityEngine.Object>;
        for (int index = 0; index < assetList.Count; index++)
        {
            AddAsset(assetList[index]);
        }
    }
    else
    {
        if (pResult is AudioClip)
            AddAudioClip(pResult);
        else if (pResult is GameObject)
            AddGameObject(pResult);
        else if (pResult is TextAsset)
            AddTextAsset(pResult);
        else if (pResult is Texture)
            AddTexture(pResult);
        else if (pResult is Sprite)
            AddSprite(pResult);
    }
}

private void AddAudioClip(object pAssetObject)
{
    AudioClip audioClip = pAssetObject as AudioClip;
    if (!mAudioClipDictionary.ContainsKey(audioClip.name))
        mAudioClipDictionary.Add(audioClip.name, audioClip);
}

private void AddGameObject(object pAssetObject)
{
    GameObject gameObj = pAssetObject as GameObject;
    if (!mGameObjectDictionary.ContainsKey(gameObj.name))
        mGameObjectDictionary.Add(gameObj.name, gameObj);
}

        ResourceManager为每一个类型的资源定义了获取资源的方法。这里之所以为每一个类型都定义一个接口,是为了在调用ResourceManager的资源获取接口时,清楚的知道有哪些接口可以使用,并清楚的知道接口返回什么类型的结果。

public AudioClip GetAudioClip(string pAudioClipName)
{
    if (mAudioClipDictionary.ContainsKey(pAudioClipName))
        return mAudioClipDictionary[pAudioClipName];
    else
        return null;
}

public GameObject GetGameObject(string pGameObjectName)
{
    if (mGameObjectDictionary.ContainsKey(pGameObjectName))
        return mGameObjectDictionary[pGameObjectName];
    else
        return null;
}

        最后就是移除资源的接口,与添加接口类似,每个类型的资源一一对应。

public void RemoveAsset(object pResult)
{
    if (pResult is List<UnityEngine.Object>)
    {
        List<UnityEngine.Object> assetList = pResult as List<UnityEngine.Object>;
        for (int index = 0; index < assetList.Count; index++)
        {
            RemoveAsset(assetList[index]);
        }
    }
    else
    {
        if (pResult is AudioClip)
            RemoveAudioClip(pResult);
        else if (pResult is GameObject)
            RemoveGameObject(pResult);
        else if (pResult is TextAsset)
            RemoveTextAsset(pResult);
        else if (pResult is Texture)
            RemoveTexture(pResult);
        else if (pResult is Sprite)
            RemoveSprite(pResult);
    }
}

private void RemoveAudioClip(object pAssetObject)
{
    AudioClip audioClip = pAssetObject as AudioClip;
    if (mAudioClipDictionary.ContainsKey(audioClip.name))
        mAudioClipDictionary.Remove(audioClip.name);
}

private void RemoveGameObject(object pAssetObject)
{
    GameObject gameObj = pAssetObject as GameObject;
    if (mGameObjectDictionary.ContainsKey(gameObj.name))
        mGameObjectDictionary.Remove(gameObj.name);
}

        有关ResourceManager就先介绍到这里,这里只展示了部分代码,关于完整代码,各位同学可以在文章最后获取Git下载工程。

相关链接

Release-Framework-Client客户端框架Git:https://gitee.com/huoyixian/release-framework-client

Manager模块介绍:https://blog.csdn.net/huoyixian/article/details/145613966

相关文章:

  • 新的面试题CSS
  • leetcode 416. 分割等和子集
  • DeepSeek-R1:通过强化学习提升大型语言模型推理能力的探索
  • 【机器学习】监督学习-决策树-CART(Classification and Regression Tree,分类与回归树)详尽版
  • 兔兔答题应用于微信考试、付费考试、社会调查问卷、明星知识问答、员工培训考核、模拟自测、企业面试、试题库等多种场景。
  • 【Elasticsearch】index索引相关模块
  • 使用pyCharm创建Django项目
  • 【c++】字符串 string 以及与右值结合
  • 每日一题——字符串的排列
  • STM32 HAL库UART串口数据接收实验
  • kibana es 语法记录 elaticsearch
  • Python--常见库与函数
  • Java使用Redis
  • Go语言中的panic
  • 数字内容体验案例解析与转化率提升策略
  • 问卷数据分析|SPSS实操之二元logistics分析
  • Matlab 多项式曲线拟合(三维)
  • 蓝桥杯 Java B 组之日期与时间计算(闰年、星期计算)
  • PHP场地预定小程序
  • LLM论文笔记 6: Training Compute-Optimal Large Language Models
  • 巴外交部:以军在杰宁向外交使团开火
  • 中方在世贸组织对美国“对等关税”表达关注,呼吁维护多边主义
  • 四川省政府党组成员、副省长、省公安厅厅长叶寒冰接受审查调查
  • 上海国际电影节将于6月3日公布排片表,6月5日中午开票
  • 苏丹港持续遭无人机袭击,外交部:呼吁各方保护民用设施和平民安全
  • 聚焦智能浪潮下的创业突围,“青年草坪创新创业湃对”走进北杨人工智能小镇