游戏热更教学系列(一)——AssetBundle学习

游戏热更教学系列(一)——AssetBundle学习

前言

目前的大部分的游戏现在都需要进行版本的更新,但是如果是每次更新都要重新下载完整的资源包,但是实际却只是更新了很小的一部分的话,那可能就会浪费玩家很多的流量去下载,如果本身软件的安装包就很大的话,可能就会浪费玩家很多的时间,这极可能会降低玩家的兴趣,所以就有了热更技术,每次更新的时候只需要更新一部分资源和代码就可以实现版本更新,这样就可以大大降低玩家下载的内容。

学习热更技术需要掌握的知识

想要学会热更技术,是需要掌握一些必要的知识的,热更主要就是更新游戏的资源和代码,用AssetBundle进行资源的热更,用Lua语言进行代码的热更,还需要会使用Lua的一些框架插件如XLua,toLua等。

一、AssetBundle的制作、打包与上传

AssetBundle,简称AB包,即资源包。主要就是用于资源热更,更新游戏中的资源。

1.AssetBundle的制作与打包

1.1 AB包的设置

随意选择一个资源,打开资源的Inspector面板,选择最下面的AssetBundle属性,如下:
选择的资源Inspector
如图中圆圈所示,有两个可选的框,第一个是打包后的资源包的名字,第二个你想要设置的资源包的后缀,这些都可以自己设置,注意事项:

  • 设置的相同资源名,后缀必须相同,不然打包会报错
  • 资源包的名字可以这样设置,比如“A/B”,这样设置,默认最后一个"/“所在的后面为资源包的名字,前面以”/"分隔,其他的均为打包资源包的根目录下的文件夹,会默认创建
  • 资源包所依赖的其他的资源包如果也设置了,那依赖的资源包将不会打包到该资源包中
1.2 创建生成AB包的代码

Unity没有设置生成AB包的菜单,需要自己用代码写一个生成AB包的代码,可能是考虑到AB包只能在一个平台适用,而平台很多,不好统一吧。步骤如下:

  • 在Assets文件夹下创建一个Editor文件夹
  • 在Editor文件夹下创建一个C#脚本,并命名为CreateAssetBundle(这里可以自己任意命名)
  • 代码如下:
using System.IO;
using UnityEditor;
//*************
//Author:HCL
//Time:2023-3-9
//
//**********
public class CreateAssetBundle
{
  [MenuItem("Assets/Build  AssetBundles")]//此为菜单显示的按钮,可以在菜单栏的Assets下看到Build  AssetBundles,点击后就可以生成相应的AB包了
  static void BuildAssetBundles()
  {
    string dir = "AssetBundles";//此为你想生成的AB包的文件夹根路径
    if (!Directory.Exists(dir))
    {
       Directory.CreateDirectory(dir);
     }
     //这个就是生成AB包的方法,参数说明:
     //第一个参数:生成的AB包的文件夹根路径
     //第二个参数:AB包压缩的方式,BuildAssetBundleOptions.None为默认的压缩格式
     //第三个参数:AB包使用的目标平台,只能适用一个平台
     BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
        }
    }
}

完成以上步骤就可以生成AB包了,点击菜单栏的Assets的Build AssetBundles,等待打包完成,然后去到相应的文件夹中,比如上述代码中的AssetBundles,就可以看到打包好的所有资源包了,我这里任意举一个例子,来说明一下打包后所拥有的内容:
打包后所拥有的内容
第一个就是对应的设置AB包时的文件夹路径的根路径,第二个是AssetBundles对应的所有AB包信息,第三个是AssetBundles对应的内部所有文件对应的AB包配置信息,每个打包后的根目录下都会生成这两个文件,比如打包的目录为AssetBundles,则会有AssetBundles,AssetBundles.manifest这两个文件,其他的就是对应的资源包和其对应的配置文件了,比如上图中的scenes.unity3d,这个就是打包的scenes资源包,后缀为unity3d,下面那个同名的scenes.unity3d.manifest就是其配置文件。下面主要来介绍一下两种manifest的一些内容:

  • AssetBundles.manifest(打包文件夹的配置文件)
    内容如下:
ManifestFileVersion: 0
CRC: 717295521
AssetBundleManifest:
  AssetBundleInfos:
    Info_0:
      Name: share.unity3d
      Dependencies: {}
    Info_1:
      Name: scenes.unity3d
      Dependencies:
        Dependency_0: scene/wall.unity3d
    Info_2:
      Name: scene/wall.unity3d
      Dependencies:
        Dependency_0: share.unity3d
字段信息字段含义
ManifestFileVersion所属的版本号
CRC所用的校验码,可用于校验数据是否正确,在下载时可以使用
AssetBundleInfos里面就是所有包含的内容信息了,各个信息以’Info_编号’分隔,如Info_0,Info_1,Info_2等,每个Info中,Name表示对应的资源包的相对路径,如share.unity3d指的是share.unity3d资源包, scene/wall.unity3d则指scene文件夹下的wall.unity3d资源包,Dependencies指的是每个资源包所对应的依赖包,多个依赖包以 ‘Dependency_编号’分割。
  • scenes.unity3d.manifest(scenes.unity3d资源包的配置文件(这儿随便取了其中一个资源包))
    内容如下:
ManifestFileVersion: 0
CRC: 1422320002
Hashes:
  AssetFileHash:
    serializedVersion: 2
    Hash: 82c3676a6e3a884fe1fdc072123a3fae
  TypeTreeHash:
    serializedVersion: 2
    Hash: 967e73a2549e95eedb6ef1a0d1b029f6
HashAppended: 0
ClassTypes:
- Class: 1
  Script: {instanceID: 0}
- Class: 4
  Script: {instanceID: 0}
- Class: 20
  Script: {instanceID: 0}
- Class: 21
  Script: {instanceID: 0}
- Class: 23
  Script: {instanceID: 0}
- Class: 28
  Script: {instanceID: 0}
- Class: 33
  Script: {instanceID: 0}
- Class: 43
  Script: {instanceID: 0}
- Class: 48
  Script: {instanceID: 0}
- Class: 81
  Script: {instanceID: 0}
- Class: 89
  Script: {instanceID: 0}
- Class: 104
  Script: {instanceID: 0}
- Class: 108
  Script: {instanceID: 0}
- Class: 114
  Script: {fileID: 11500000, guid: f2b4ed9184e2de0458023175f84932e4, type: 3}
- Class: 115
  Script: {instanceID: 0}
- Class: 135
  Script: {instanceID: 0}
- Class: 157
  Script: {instanceID: 0}
- Class: 196
  Script: {instanceID: 0}
SerializeReferenceClassIdentifiers: []
Assets:
- Assets/Scenes/Main.unity
Dependencies:
- "F:/UnityHigh-paying job classes/3-Advanced cases and techniques/AssetBundle\u5165\u95E8\u5230\u638C\u63E1/AssetBundleProj/AssetBundles/scene/wall.unity3d"
字段信息字段含义
ManifestFileVersion所属的版本号
CRC所用的校验码,可用于校验数据是否正确,在下载时可以使用
Assets所包含的资源名,可以在这里看到资源包的内容,如Assets/Scenes/Main.unity则表示里面有Main.unity资源,为一个场景资源
Dependencies资源包的依赖包所在路径

以上就是AB包打包后的内容介绍了。

1.3 Build的压缩方式介绍
BuildAssetBundleOptions
1.BuildAssetBundleOptions.None:使用LZMA算法压缩,压缩的包更小,但是加载
时间更长。使用之前需要整体解压。一旦被解压,这个包会使用LZ4重新压缩。
使用资源的时候不需要整体解压。在下载的时候可以使用LZMA算法,
一旦它被下载了之后,它会使用LZ4算法保存到本地上。
BuildAssetBundleOptions.UncompressedAssetBundle:不压缩,包大,加载快
BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4压缩,压缩率没有LZMA高,但是我们可以加载指定资源而不用解压全部。注意使用LZ4压缩,可以获得可以跟不压缩想媲美的加载速度,而且比不压缩文件要小。

2.AssetBundle的加载与资源的读取

AssetBundle包打包好了以后,我们就需要能够加载AB包了,这儿总共有四种加载AB包的方式:

1,AssetBundle.LoadFromMemory
2,AssetBundle.LoadFromFile
3,WWW.LoadFromCacheOrDownload
4,UnityWebRequest

下面将一一介绍:
假设我加载 AssetBundles/cubewall.unity3d资源包里面的CubeWall游戏物体,类型是GameObject,各个加载方式如下:

2.1 AssetBundle.LoadFromMemory

从内存加载AB包,是从本地进行加载的

//同步加载
 void LoadABFromMemory()
 {
        string path = "AssetBundles/cubewall.unity3d";//加载的路径
        //参数:读取到的AB包的内容的字节数组,为byte[]类型
        AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(path));
        GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeWall");
}
    //异步加载
    IEnumerator LoadABFromMemoryAsync()
    {
        string path = "AssetBundles/cubewall.unity3d";//加载的路径
        AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
        yield return request;
        AssetBundle ab = request.assetBundle;
        GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeWall");
    }
2.2 AssetBundle.LoadFromFile

与2.1类似,也是从本地加载,根据路径加载

    //同步加载
    void LoadABFromFile()
    {
        string path = "AssetBundles/cubewall.unity3d";//加载的路径
        //参数:AB包所在路径
        AssetBundle ab = AssetBundle.LoadFromFile(path);
        GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeWall");
    }
    //异步加载
    IEnumerator LoadABFromFileAsync()
    {
        string path = "AssetBundles/cubewall.unity3d";//加载的路径
        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);
        yield return request;
        AssetBundle ab = request.assetBundle;
        GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeWall");
    }
2.3 WWW.LoadFromCacheOrDownload

可下载读取网络上的AB包,也可以读取本地的AB包

IEnumerator LoadABFormWWWCaching()
{
        //首先判断缓存是否准备好
        while (Caching.ready == false)
        {
            yield return null;
        }
        string path = "AssetBundles/cubewall.unity3d";
        //本地完整路径,注意,前面需要加上"file://"或"file:///"
        string localFilePath = @"file:/E:\Unity Project Workspace\AssetBundleProject\" + path;
        //网站上的路径uri
        string netFilePath = @"http://localhost/" + path;
        //假设从网站下载,第一个参数为路径,第二个参数为指定的版本号
        WWW www = WWW.LoadFromCacheOrDownload(netFilePath, 1);
        yield return www;
        if (string.IsNullOrEmpty(www.error) == false)
        {
            Debug.Log(www.error); 
            yield break;
        }
        AssetBundle ab = www.assetBundle;
        GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeWall");
}
2.4 UnityWebRequest

与2.3类似,可下载读取网络上的AB包,也可以读取本地的AB包

    IEnumerator LoadABFromUnityWebRequest()
    {
        string path = "AssetBundles/cubewall.unity3d";
        //本地完整路径,注意,前面需要加上"file://"或"file:///"
        string localFilePath = @"file:/E:\Unity Project Workspace\AssetBundleProject\" + path;
        //网站上的路径uri
        string netFilePath = @"http://localhost/" + path;
        //假设从网站下载,第一个参数为路径,第二个参数为指定的版本号
        UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(netFilePath);
        yield return request.SendWebRequest();
        //AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
        AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
        //使用里面的资源
        GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeWall");
    }

3.AssetBundleManifest的相关操作

AssetBundleManifest即整个AB包的文件夹对应的manifest配置文件,可以获得与AB包对应的配置信息

//打包的目录文件夹对应的AB包
AssetBundle manifestAB =  AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
//获取该AB包对应的manifest文件,注意
AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//输出该manifest文件下的所有AB包的名字
foreach(string name in manifest.GetAllAssetBundles())
{
  print(name);
 }
 //获取cubewall.unity3d资源包所有的依赖包路径
string[] strs =  manifest.GetAllDependencies("cubewall.unity3d");
//输出并加载cubewall.unity3d资源包的依赖包
foreach (string name in strs)
{
  print(name);
  AssetBundle.LoadFromFile("AssetBundles/" + name);
}

4.AssetBundle的卸载

当所加载的AB包不再使用时,为了留出更多的内存空间,需要对不使用的AB包进行卸载。主要是通过AssetBundle.Unload函数进行卸载,但是根据参数有些差别。

1、AssetBundle.Unload(true):卸载所有资源,即使有资源被使用着也会卸载
	适用的场景:
	1)在关切切换、场景切换
	2)资源没被用的时候调用
2、AssetBundle.Unload(false)卸载所有没用被使用的资源,正在使用的资源不会被卸载
	个别资源怎么卸载:
	1)通过 Resources.UnloadUnusedAssets.	
	2)场景切换的时候	

5.AssetBundle浏览工具

这个工具可以很方便的让你在项目中浏览你所有设置的AB包,AB包的大小,AB包的内容,还可以查看项目外的其他AB包,帮助你打AB包。
github:Unity Asset Bundle Browser tool

总结

以上就是今天要讲的内容,本文介绍了AssetBundle包的创建、使用、加载和卸载等整个流程,AB包为我们实现资源的更新做好了准备,是热更新中的一个重要的环节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值