TheLudGamer 发表于 2022-3-30 12:18

2022-03-29Unity使用AssetBundle(AB包)实现资源的打包,加载和卸载

看不懂正常我是写给自己看的

Asset同步异步引用计数资源加载管理器[(10条消息) Unity开发(五) Asset同步异步引用计数资源加载管理器(https://blog.csdn.net/wowo1gt/article/details/101296295)

Prefab加载自动化管理引用计数管理器

加载框架设计
Asset加载,要内部衔接多种资源加载方式,对外部隐藏底层资源加载逻辑。
内部主要管理三种加载方式
                                                 AssetBundleLoadMgr负责ab文件资源的加载 AssetsLoadMgr                        ResourcesLoadMgr负责Resources目录下资源加载                                                EditorAssetLoadMgr负责Editor模式下资源加载
private Dictionary<string, AssetObject> _loadingList; //加载队列
private Dictionary<string, AssetObject> _loadedList;//完成队列
private Dictionary<string, AssetObject> _unloadList;//卸载队列
private List<AssetObject> _loadedAsyncList; //异步加载队列,延迟回调
private Queue<PreloadAssetObject> _preloadedAsyncList; //异步预加载,空闲时加载
主体就三个队列,加载队列、完成队列和销毁队列,跟大部分开发者的资源管理大同小异

当一个异步加载开始,创建Asset单元放入加载队列
当异步加载结束,将Asset单元移入完成队列
外部调用卸载,引用计数为0的Asset单元放入卸载队列
卸载队列中延期卸载时间结束,真正卸载
这边还有2个特殊队列,预加载队列和异步加载队列
预加载队列实现的是——当加载队列为空情况下,取1个创建Asset单元放入加载队列
异步加载队列实现的是——当资源已经加载完成,但需要异步回调时,延帧回调
我们可以考虑,我们异步加载一个资源,资源已存在,直接运行回调函数。
而这个时候,外部代码很可能还没设定好必要的逻辑,代码逻辑实际希望的是异步回调,在运行完逻辑设定之后。
所以,为了保证外部逻辑的正确性,就算资源已经加载好,也要异步回调,所以必须要有异步加载队列。

开发一般要使用AssetBundle对资源进行打包,加载和卸载
AssetBundle的相关API

(https://blog.csdn.net/qq_51026638/article/details/117253383?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164853789316780255239317%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164853789316780255239317&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-117253383.142v5control,143v6register&utm_term=AssetBundleAPI&spm=1018.2226.3001.4187)
Unity资源加载
Unity资源类型,按加载流程顺序,有三种

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

游戏资源一般来说只有在被使用到或即将被使用到时才应该被加载进内存中,不应该一直出现在场景里。很容易理解,我刚打开游戏的第一关,我需要将第10关的BOSS提前在内存中加载好吗?这无疑是对内存空间的极大浪费,所以我们要对资源进行合理的加载和卸载,使用时加载,用完后卸载。
Unity对资源进行加载和卸载主要有两种方式:Resources和AssetBundle。AssetBundle相比于Resources来说,最主要的优势就是对于游戏的资源热更新。比如说,我现在有一个安装包1G大小的手游,现在有一个1M大小的资源A出问题了,我将这个资源A替换成了另一个同样1M大小的资源B,此时差距就出现了:
(1)如果我使用Resources管理资源,资源是全部存储在安装包中的,那么我替换完成后,为了让用户同步到这次的资源更新,我得再重新将整个游戏打一个新的包,也就是说,仅仅是替换了一个1M的资源,用户却必须重新下载1G的新包进行安装。这无论是从效率上还是用户体验上来说都是非常差劲的。
(2)如果我使用AssetBundle管理资源,资源是和安装包分离,单独打包的。而且一个游戏的资源一般会按照类型或是逻辑分成很多小包,游戏运行时需要用到什么资源就从对应的包中读取相应的资源。如此一来,当我们替换资源A后,只需要将A资源所在的包(bundle)进行更新,重新将这个bundle发布给用户,直接覆盖原先的bundle即可,替换一个1M的资源可能只需要用户下载2-10M即可完成,基本保证了用户无需下载未改动的部分


1648537723(1).png

必须在Asset下创建一个叫Editor的文件夹,脚本必须放在Editor文件夹下才能使用。Windows平台的路径可以随意选择,Andriod和IOS的存储路径是约定好不能变更的。
using UnityEditor;
using System.IO;
public class AssetBuldle : Editor
{

static void CreatAssetBundle(){    string path = "Assets/StreamingAssets";    if (!Directory.Exists(path))    {      Directory.CreateDirectory(path);    }    BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.Android);    UnityEngine.Debug.Log("Android Finish!");}static void BuildAllAssetBundlesForIOS(){    string dirName = "AssetBundles/IOS";    if (!Directory.Exists(dirName))    {      Directory.CreateDirectory(dirName);    }    BuildPipeline.BuildAssetBundles(dirName, BuildAssetBundleOptions.CollectDependencies, BuildTarget.iOS);    UnityEngine.Debug.Log("IOS Finish!");}static void CreatPCAssetBundleForwINDOWS(){    string path = "AB";    if (!Directory.Exists(path))    {      Directory.CreateDirectory(path);    }    BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);    UnityEngine.Debug.Log("Windows Finish!");}
}
将该脚本放入Editor文件夹下之后,上方菜单栏就会出现Toos的选项,[图片上传失败...(image-594e9a-1648538209998)]

此时在勾选好需要打包的资源后选择对应的平台就可以一键打包了,比如点击Windows的打包,等待一会,下方日志就会显示
[图片上传失败...(image-310e57-1648538217414)]

此时可以去看其所在的路径,该脚本Windows的存储路径在工程文件下的AB文件夹中

三、Unity 加载和卸载AssetBundle
加载和卸载直接在脚本中使用相关API即可,下面是一个简单的小测试。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ABtest : MonoBehaviour
{
string path = "AB/jojo.czh";//包体的路径
private AssetBundle asset;//声明一个AB包
void Update()
{
    if (Input.GetKeyDown(KeyCode.L))    {      asset = AssetBundle.LoadFromFile(path);      asset.LoadAsset("jojo");//通过资源名加载单个资源      asset.LoadAsset("Giorno");      //asset。LoadAllAsset() 加载全部资源      Debug.Log("Load AssetBundle");    }    if (Input.GetKeyDown(KeyCode.U))    {      asset.Unload(true);//卸载全部资源      Debug.Log("Unload AssetBundle");    }}
}
页: [1]
查看完整版本: 2022-03-29Unity使用AssetBundle(AB包)实现资源的打包,加载和卸载