当前位置:   article > 正文

Unity开发(五) Asset同步异步引用计数资源加载管理器_unity loadassetsasync callback

unity loadassetsasync callback

前言

本文是Asset资源加载,是文章(AssetBundle加载)的后续,读者可以先阅读上篇文章,再理解和使用这篇文章。

Asset加载框架

任何框架,都是从原理,到设计,然后实现,最后优化。
先讲讲原理。

Unity的资源加载

Unity最通用的资源加载方式,就三种

  1. Resources资源加载(Runtime和Editor模式)
  2. AssetBundle资源加载(Runtime和Editor模式)
  3. AssetDataBase资源加载(Editor模式)

大部分游戏,为了热更和效率考虑,都是——

  1. Runtime时,绝大部分资源使用AssetBundle,极少数资源使用Resources
  2. Editor时,使用AssetDataBase为主,Resources为辅

那么,我们的设计就要包含这三种加载方式。

Unity资源类型,按加载流程顺序,有三种

  1. AssetBundle 资源以压缩包文件存在(Resources目录下资源打成包体后也是以ab格式存在)
  2. Asset 资源在内存中的存在格式
  3. GameObject 针对Prefab导出的Asset,可实例化
加载
Prefab实例化
AssetBundle
Asset
GameObject

Unity启动的时候,会将Resources目录下资源的ab加载到内存中,所以我们能直接使用Resources.Load()来加载资源。

针对AssetBundle 的加载,读者可以参阅AssetBundle同步异步引用计数资源加载管理器,下文中的
针对Asset 的加载,本文会作讲解,并提供整套方案和代码
针对GameObject的加载,读者可以参阅Prefab加载自动化管理引用计数管理器

依据上面的需求,我们来设计并实现一套Asset资源加载管理器吧。

加载框架设计

Asset加载,要内部衔接多种资源加载方式,对外部隐藏底层资源加载逻辑。
内部主要管理三种加载方式

AssetsLoadMgr
AssetBundleLoadMgr
ResourcesLoadMgr
EditorAssetLoadMgr
负责ab文件资源的加载
负责Resources目录下资源加载
负责Editor模式下资源加载

我们能在后续代码中看到很多如下的写法

public bool IsAssetExist(string _assetName)
{
   
#if UNITY_EDITOR && !TEST_AB
    return EditorAssetLoadMgr.I.IsFileExist(_assetName);
#else
    if (ResourcesLoadMgr.I.IsFileExist(_assetName)) return true;
    return AssetBundleLoadMgr.I.IsABExist(_assetName);
#endif
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

UNITY_EDITORTEST_AB限定了Runtime和Editor模式,隐藏了内部逻辑,在Editor下也可以打开ab加载的开关,测试ab加载是否正确,逻辑是否正常。
EditorAssetLoadMgrResourcesLoadMgrAssetBundleLoadMgr都有通用的4个接口——IsFileExistLoadAsyncLoadSyncUnload

内部是对资源方式的封装,外部接口提供了类似的通用接口

外部接口
文件存在
预加载
异步
同步
卸载
刷新
每帧调用
IsFileExist
PreLoad
LoadAsync
LoadSync
Unload
Update
AssetsLoadMgr
主线程

当然,本文底部源码里,还有很多函数实现了特定功能,例如RemoveCallBackAddAssetAddAssetRef等,这些只是功能性的函数,并不影响主体结构,就不展开讲了。

外部结构,内部结构都定义好了,我们开始实现逻辑。

Update才是王道

要Update,先从队列开始

private Dictionary<string, AssetObject> _loadingList; //加载队列
private Dictionary<string, AssetObject> _loadedList;  //完成队列
private Dictionary<string, AssetObject> _unloadList;  //卸载队列
private List<AssetObject> _loadedAsyncList; //异步加载队列,延迟回调
private Queue<PreloadAssetObject> _preloadedAsyncList; //异步预加载,空闲时加载
  • 1
  • 2
  • 3
  • 4
  • 5
UpdatePreload
UpdateLoading
UpdateLoadAsync
UpdateUnLoad
预加载队列
加载队列
完成队列
异步加载队列
销毁队列

主体就三个队列,加载队列完成队列销毁队列,跟大部分开发者的资源管理大同小异

  1. 当一个异步加载开始,创建Asset单元放入加载队列
  2. 当异步加载结束,将Asset单元移入完成队列
  3. 外部调用卸载,引用计数为0的Asset单元放入卸载队列
  4. 卸载队列中延期卸载时间结束,真正卸载

这边还有2个特殊队列,预加载队列异步加载队列
预加载队列实现的是——当加载队列为空情况下,取1个创建Asset单元放入加载队列
异步加载队列实现的是——当资源已经加载完成,但需要异步回调时,延帧回调

Update
UpdatePreload
UpdateLoadAsync
UpdateLoading
UpdateUnload
加载队列为空时从预加载队列取一个加入
异步加载队列运行回调
加载完成放入完成队列
卸载资源延迟过期真正卸载

具体代码实现,查看底部代码,具体就不详细说明啦。

TIP:为什么要有异步加载队列

我们可以考虑,我们异步加载一个资源,资源已存在,直接运行回调函数。
而这个时候,外部代码很可能还没设定好必要的逻辑,代码逻辑实际希望的是异步回调,在运行完逻辑设定之后。
所以,为了保证外部逻辑的正确性,就算资源已经加载好,也要异步回调,所以必须要有异步加载队列

开始异步加载

先来看一下加载单元的数据结构

private class AssetObject
{
   
    public string _assetName;

    public int _lockCallbackCount; //记录回调当前数量,保证异步是下一帧回调
    public List<AssetsLoadCallback> _callbackList = new List<AssetsLoadCallback>(); //回调函数

    public 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/341561
推荐阅读
相关标签
  

闽ICP备14008679号