Unity游戏资源更新(AB包)

目录

前言:

一、什么是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);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/286913.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设计模式:单例模式

文章目录 1、概念2、实现方式1、懒汉式2、饿汉式3、双检锁/双重校验锁4、登记式/静态内部类5、枚举6、容器实现单例 1、概念 单例模式&#xff08;Singleton Pattern&#xff09;是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创…

Linux引导过程与服务控制

目录 一、操作系统引导过程 1. 过程图示 2. 步骤解析 2.1 bios 2.2 mbr 2.3 grup 2.4 加载内核文件 3. 过程总结 4. centos6和centos7启动区别 5. 小结 二、服务控制及切换运行级别 1. systemd核心概念 2. 运行级别 3. Systemd单元类型 4. 运行级别所对应的Syst…

YOLOv8改进 | 检测头篇 | DynamicHead原论文一比一复现 (不同于网上版本,全网首发)

一、本文介绍 本文给大家带来的改进机制是DynamicHead(Dyhead),这个检测头由微软提出的一种名为“动态头”的新型检测头,用于统一尺度感知、空间感知和任务感知。网络上关于该检测头我查了一些有一些魔改的版本,但是我觉得其已经改变了该检测头的本质,因为往往一些细节上才…

【安卓的签名和权限】

Android 编译使用哪个key签名&#xff1f; 一看Android.mk 在我们内置某个apk的时候都会带有Android.mk&#xff0c;这里面就写明了该APK使用的是什么签名&#xff0c;如&#xff1a; LOCAL_CERTIFICATE : platform表明使用的是platform签名 LOCAL_CERTIFICATE : PRESIGNED…

MPI并行程序设计 —— C 和 fortran 环境搭建 openmpi 示例程序

1.安装环境 wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.6.tar.g tar zxf openmpi-4.1.6.tar.gz cd openmpi-4.1.6/ 其中 configure 选项 --prefix/.../ 需要使用绝对路径&#xff0c;例如&#xff1a; ./configure --prefix/home/hipper/ex_open…

使用UDP和JSON在C#中高效发送结构体数据

使用UDP和JSON在C#中高效发送结构体数据 引言 在许多网络编程场景中&#xff0c;我们经常需要在不同的应用程序或服务之间发送和接收数据。UDP&#xff08;用户数据报协议&#xff09;因其低延迟和少开销的特点&#xff0c;在需要快速数据传输的场景中非常有用。本文介绍了如何…

VS 2022 控制台程序运行时不显示控制台

Visual Studio 2022&#xff0c;C#控制台程序运行时不显示控制台。此外&#xff0c;C#程序修改运行时的程序名。 文章目录 不显示控制台修改运行时的程序名打包成.exe 文件 不显示控制台 1 选中需要项目&#xff0c;右击属性&#xff0c;选中常规。 2 将输出类型从控制台改为…

介绍两本书《助推》与《耐力》

冠历最后一年已经养成了没有冲突的情况下每天跑步、读书的习惯&#xff0c;今天突发奇想&#xff1a;是否重新挑战下每日写作。 ​ 今天介绍两本书。第一本是《助推》&#xff0c;这本书是由于真友 吾真本 的介绍开始读的。 一句话介绍这本书&#xff0c;那就是&#xff1a;如果…

MySQL将多条数据合并成一条的完整示例

数据库中存的是多条数据&#xff0c;展示的时候需要合并成一条 数据表存储形式如下图 以type分组&#xff0c;type相同的算一条&#xff0c;且保留image和link的所有数据&#xff0c;用groupBy只保留一条数据 解决方案&#xff1a;用GROUP_CONCAT 完整语法如下 group_concat…

Go后端开发 -- main函数 变量 常量 函数

Go后端开发 – main函数 & 变量 & 常量 & 函数 文章目录 Go后端开发 -- main函数 & 变量 & 常量 & 函数一、第一个main函数1.创建工程2.main函数解析 二、变量声明1.单变量声明2.多变量声明 三、常量1.常量的定义2.优雅的常量 iota 四、函数1.函数返回…

【FPGA/verilog -入门学习15】vivado FPGA 数码管显示

1&#xff0c;需求&#xff1a;使用xc720 开发板的8个数码管显示12345678 2&#xff0c;需求分析&#xff1a; 75hc595 1&#xff0c;74hc595驱动&#xff0c;将串行数据转换成并行输出。对应研究手册 2&#xff0c;发送之前将要发的数据&#xff0c;合并成高8位:SEG,低8位&…

二蛋赠书十三期:《一书读懂物联网》

前言 大家好&#xff01;我是二蛋&#xff0c;一个热爱技术、乐于分享的工程师。在过去的几年里&#xff0c;我一直通过各种渠道与大家分享技术知识和经验。我深知&#xff0c;每一位技术人员都对自己的技能提升和职业发展有着热切的期待。因此&#xff0c;我非常感激大家一直…

代码随想录算法训练DAY18|二叉树5

算法训练DAY18|二叉树5 513.找树左下角的值 力扣题目链接 给定一个二叉树&#xff0c;在树的最后一行找到最左边的值。 示例 1: 示例 2: 思路 本题要找出树的最后一行的最左边的值。此时大家应该想起用层序遍历是非常简单的了&#xff0c;反而用递归的话会比较难一点。 我…

云原生学习系列之基础环境准备(虚拟机搭建)

最近由于工作需要开始学习云原生相关内容&#xff0c;为方便学习操作&#xff0c;准备在外网搭建自己的环境&#xff0c;然后进行相关的练习&#xff0c;搭建环境的第一步便是虚拟机的安装。 基础软件 这里我用到的是CentOS-7-x86_64的操作系统。 链接&#xff1a;https://pa…

使用宝塔在Linux面板搭建网站,并实现公网远程访问

文章目录 前言1. 环境安装2. 安装cpolar内网穿透3. 内网穿透4. 固定http地址5. 配置二级子域名6. 创建一个测试页面 前言 宝塔面板作为简单好用的服务器运维管理面板&#xff0c;它支持Linux/Windows系统&#xff0c;我们可用它来一键配置LAMP/LNMP环境、网站、数据库、FTP等&…

【Web】CTFSHOW元旦水友赛部分wp

目录 ①easy_include ②easy_web ③easy_login web一共5题&#xff0c;我出了3题&#xff0c;巧的是好像师傅们也只出了3题&#xff0c;跨年拿旗还是很快乐的&#xff0c;下面直接贴出自己的wp. ①easy_include pearcmd不解释 这里主要是 &#xff0c;file://协议支持以fi…

CSS animation动画和关键帧实现轮播图效果HTML

CSS animation动画和关键帧实现轮播图效果HTML 这轮播图效果使用h5和css3实现效果&#xff0c;不需要js控制&#xff0c;但是其中的缺点就是不能使用鼠标进行切换效果。 具有代码如下 <!DOCTYPE html> <html lang"en"><head><meta charset&quo…

使用echarts的bmap配置项绘制区域轮廓遮罩

示例图 代码 <template><div id"map" style"width: 100%; height: 100vh"></div> </template><script> import * as echarts from "echarts"; import "echarts/extension/bmap/bmap"; export default…

第28关 k8s监控实战之Prometheus(一)

------> 课程视频同步分享在今日头条和B站 大家好&#xff0c;我是博哥爱运维。对于运维开发人员来说&#xff0c;不管是哪个平台服务&#xff0c;监控都是非常关键重要的。 在传统服务里面&#xff0c;我们通常会到zabbix、open-falcon、netdata来做服务的监控&#xff0…

Zookeeper之Java客户端实战

ZooKeeper应用的开发主要通过Java客户端API去连接和操作ZooKeeper集群。可供选择的Java客户端API有&#xff1a; ZooKeeper官方的Java客户端API。第三方的Java客户端API&#xff0c;比如Curator。 接下来我们将逐一学习一下这两个java客户端是如何操作zookeeper的。 1. ZooKe…