Unity游戏资源更新(AB包)

发布时间:2024年01月02日

目录

前言:

一、什么是AssetBundle

二、AssetBudle的基本使用

1.AssetBundle打包

2.BuildAssetBundle

BuildAssetBundleOptions

BuildTarget

示例

3.AssetBundle的加载

LoadFromFile

LoadFromMemory

LoadFromMemoryAsync

UnityWebRequestAsssetBundle


前言:

随着移动终端的发展,在一些大型游戏中动态加载游戏模型、贴图等资源文件以及实现游戏的更新,对开者来说是非常重要的工作。本文将结合Unity的AssetBundle资源包来做到游戏的更新。

一、什么是AssetBundle

AssetBundle是将资源用Unity提供的一种用于存储资源的压缩格式打包后的集合,它是对资源管理的扩展,可以动态地加载和写在,并大大减少游戏所占地内存,即使是已经发布地游戏也可以用它来增加新的内容。

一般情况下,AssetBundle开发流程地具体步骤如下:

1)创建AssetBundle。开发人员在Unity中通过脚本将所需要地资源打包成AssetBundle文件。

2)上传至服务器。开发者将创建好的AssetBundle文件通过上传工具上传到游戏地服务器中,让游戏客户端可以通过访问服务器来获得当前需要地资源,进而实现游戏的更新。

3)下载AssetBundle。游戏运行时,客户端可以将服务器上的游戏更新所需要的AssetBundle下载到本地设备,再通过加载模块加载到游戏中。Unity提供了相应的API来完成从服务器的下载AssetBundle操作。

4)加载AssetBundle。AssetBundle文件下载完成后,通过Unity提供的API可以加载资源里的模型、贴图、音频等并将它们实例化更新到游戏客户端。

5)卸载AssetBundle,Unity提供了相应的方法来卸载AssetBundle,卸载它可以节约内存。

二、AssetBudle的基本使用

1.AssetBundle打包

Unity有自带的打包创建工具,开发者可以一目了然的打包而不需要任何代码。

步骤:

1)选中我们需要打包的资源,在我的示例项目中,有一个名为CubeAsset的预制件

2)在Inspector面板可以看到最底下的AssetBundle选项,现在为None

3)展开选项创建新的AssetBundle。(点击New命名)

注意:只有Asset目录下的资源文件可以被打包到AssetBundle中,AssetBundle的名称固定为小写字母,如果使用了大写,系统会自动转换为小写。每个AssetBundle都可以设置一个Variant,Variant其实是一个后缀,如果有不同分辨率的同名资源,可以添加不同的Variant来加以区分。

2.BuildAssetBundle

创建好的AssetBundle需要导出,这一过程需要编写代码来实现。

Unity简化了开发者遍历资源的过程,自行打包时会将规定的所有资源打包(即之前用打包工具创建并且命名的全部资源),然后将它们置于指定的文件夹中,其声明格式如下:

public static AssetBundleMainfest BuildAseetBundles(string outputPath,BuildAssetBundleOptions assetBundleOptions=BuildAssetBundleOption.None,BuildTarget targetPlatfom=BuildTarget.WebPlayer);

其中,outputPath参数是AssetBundle的输出路径,一般情况下为Assets目录下的某一个文件,如:Application.dataPath+"/AssetBundle"; assetBundleOptions参数为AssetBundle的创建选项; BuildTarget参数为AssetBundle的目标创建平台。?

BuildAssetBundleOptions

None不使用任何特殊选项构建 assetBundle。
UncompressedAssetBundleDon't compress the data when creating the AssetBundle.
DisableWriteTypeTree不包括 AssetBundle 中的类型信息。
DeterministicAssetBundle使用存储在资源包中对象的 ID 的哈希构建资源包。
ForceRebuildAssetBundle强制重新构建 assetBundle。
IgnoreTypeTreeChanges在执行增量构建检查时忽略类型树更改。
AppendHashToAssetBundleName向 assetBundle 名称附加哈希。
ChunkBasedCompression创建 AssetBundle 时使用基于语块的 LZ4 压缩。
StrictMode如果在此期间报告任何错误,则构建无法成功。
DryRunBuild进行干运行构建。
DisableLoadAssetByFileName禁用按照文件名称查找资源包 LoadAsset。
DisableLoadAssetByFileNameWithExtension禁用按照带扩展名的文件名称查找资源包 LoadAsset。
AssetBundleStripUnityVersion在构建过程中删除存档文件和序列化文件头中的 Unity 版本号。

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

BuildTarget

StandaloneOSX构建一个 macOS 独立平台(Intel 64 位)。
StandaloneWindows构建一个 Windows 独立平台。
iOS构建一个 iOS 播放器。
Android构建 Android .apk 独立平台应用程序。
StandaloneWindows64构建一个 Windows 64 位独立平台。
WebGLWebGL。
WSAPlayer构建一个 Windows 应用商店应用程序播放器。
StandaloneLinux64构建一个 Linux 64 位独立平台。
PS4构建一个 PS4 独立平台。
XboxOne构建一个 Xbox One 独立平台。
tvOS构建到 Apple 的 tvOS 平台。
Switch构建一个 Nintendo Switch 播放器。
Stadia构建一个 Stadia 独立平台。
CloudRenderingBuild a CloudRendering standalone.
PS5Build to PlayStation 5 platform.

示例

1)在Assets目录下创建一个Editor文件夹,在Editor文件夹创建一个新的c#脚本

2)输入代码

using UnityEditor;
public class BuildAsset:Editor
{
   [MenuItem("Test/BuildAssetBundles")]
   static void BuildAssetBundle()
    {
        BuildPipeline.BuildAssetBundles("./AssetBundle", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
    }
}

其中我们类继承了Editor使用了MenItem特性,我们可以在菜单栏找到Test下的BuildAssetBundle启用BuildAssetBundle方法。

在编写的输出路径中./表示在当前项目的根目录上,一般输出路径不放在Assets目录下(Assets目录:Application.dataPath)?【注意需要提前创建好输出路径的文件夹

在打包出来的文件中,如下:

每一个AssetBundle资源都有一个和原文件相关的.mainfest文本类型文件,该文件提供了所有打包资源的CRC(Cyclic Redundancy Check,循环冗余校验)和资源依赖信息。?【如cube.mainifest文件】

除此之外还有一个.mainfest文件,该文件也是文本类型文件,记录了整个 AssetBundle文件夹的信息,包括资源的列表和各个列表之间的依赖关系。

打包好的这些文件需要上传到开发平台供客户端下载,这样就可以达到更新游戏的目的。

3.AssetBundle的加载

LoadFromFile

public static AssetBundle?LoadFromFile(string?path, uint?crc, ulong?offset);

path磁盘上文件的路径。
crc未压缩内容的可选 CRC-32 校验和。如果该值不为零,则在加载内容之前,将内容与校验和进行比较,如果不匹配,则给出错误。
offset可选的字节偏移量。此值指定从何处开始读取 AssetBundle。

从磁盘上的文件同步加载 AssetBundle。

该函数支持任何压缩类型的捆绑包。 在lzma压缩的情况下,数据将被解压缩到内存中。可以直接从磁盘读取未压缩和块压缩的捆绑包。

与?LoadFromFileAsync?相比,此版本是同步的,在完成 AssetBundle 对象的创建之前不会返回。

这是加载 AssetBundle 的最快方法。

using UnityEngine;
using System.Collections;
using System.IO;

public class LoadFromFileExample : MonoBehaviour
{
    void Start()
    {
         var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine("./AssetBundle","cube"));
        if (myLoadedAssetBundle == null)
        {
            Debug.Log("Failed to load AssetBundle!");
            return;
        }

        var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("CubeAsset");
        Instantiate(prefab);

        myLoadedAssetBundle.Unload(false);
    }
}

从本地存储中加载未压缩的捆绑包时,此 API 非常高效。如果捆绑包未压缩或采用了数据块 (LZ4) 压缩方式,LoadFromFile 将直接从磁盘加载捆绑包。使用此方法加载完全压缩的 (LZMA) 捆绑包将首先解压缩捆绑包,然后再将其加载到内存中。

LoadFromMemory

public static?AssetBundle?LoadFromMemory(byte[]?binary, uint?crc);

binary包含 AssetBundle 数据的字节数组。
crc未压缩内容的可选 CRC-32 校验和。如果该值不为零,则在加载内容之前,将内容与校验和进行比较,如果不匹配,则给出错误。

从内存区域同步创建 AssetBundle。

使用此方法从字节数组创建 AssetBundle。当下载了加密数据并需要从未加密的字节创建 AssetBundle 时,这很有用。

与?LoadFromMemoryAsync?相比,此版本是同步的,在完成 AssetBundle 对象的创建之前不会返回。

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

public class Test : MonoBehaviour
{

   void Start()
    {
        //异步加载的一个变形同步加载,传入具有AssetBundle数据的字节数组
        AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(Path.Combine("./AssetBundle", "cube")));

        GameObject wallPrefab = ab.LoadAsset<GameObject>("CubeAsset");//获取这个名字的游戏物体

        Instantiate(wallPrefab);//实例化这个游戏物体
    }
}

LoadFromMemoryAsync

public static?AssetBundleCreateRequest?LoadFromMemoryAsync?(byte[]?binary, uint?crc);

binary包含 AssetBundle 数据的字节数组。
crc未压缩内容的 CRC-32 校验和(可选)。如果该参数不为零,则加载前将内容与校验和进行比较,如果不匹配则给出错误。
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class Test : MonoBehaviour
{

    IEnumerator Start()
    {
            //打开二进制数组文件,并将打开的数据传进去
            AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(Path.Combine("./AssetBundle","cube")));

            yield return createRequest;//等待加载时间

            AssetBundle ab = createRequest.assetBundle;//获取加载出来的东西

            GameObject prefab = ab.LoadAsset<GameObject>("CubeAsset");
            Instantiate(prefab);

    }
}

从内存区域异步创建 AssetBundle。

使用该方法可从一个字节数组异步创建 AssetBundle。当使用 UnityWebRequest 下载了加密数据并需要从未加密的字节创建 AssetBundle 时,这非常有用。

与?LoadFromMemory?相比,该版本将在后台线程上执行 AssetBundle 解压缩,不会立即创建 AssetBundle 对象。

UnityWebRequestAsssetBundle

使用UnityWebRequestAssetBundle.GetAssetBundle(string uri)到服务器下载AB包,现在官方推荐的主流方式,以前使用的WWW方式下载,还有UnityWebRequest.GetAssetBundle(string uri)这两种方式都已经弃用了;使用这个方式不但可以下载服务器上的资源,同时他也可以加载本地的资源,但是强烈建议如果要加载本地资源,还是使用本地同步/异步加载的方式比较妥当

  string uriPath = @"file://E:\unity\AB\AssetBundle\cube";
    private void Start()
    {
        StartCoroutine(MyUnityWebRequest());
    }
    IEnumerator MyUnityWebRequest()
    {
        //本地加载路径前面要加上file://否则会出错
        //string uriPath = @"file://D:\Unity3D_Project\Advanced\Asset Bundle Project\AssetBundles\cubewall.unity3d";
        //UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uriPath);

        //服务器上下载
        //UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(urlPath);

        //本地上下载
        UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uriPath);
        yield return request.SendWebRequest();

        if (string.IsNullOrEmpty(request.error) == false)//判断下载有没有出错,request.error表示错误信息
        {
            Debug.Log(request.error);//输出错误
            yield break;//退出携程
        }

        //AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);//获取下载到的资源

        //获取资源的另外一种方式,直接获取到UnityWebRequest下载到的东西然后强转成DownloadHandlerAssetBundle,然后再获取到AssetBundle
        AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;

        GameObject prefab = ab.LoadAsset<GameObject>("CubeAsset");

        Instantiate(prefab);
    }

文章来源:https://blog.csdn.net/m0_68267247/article/details/135325380
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。