Unity热更新 AssetBundle
在游戏开发中,常常需要用到热更新技术。比如:一个手机游戏开发好后,用户安装到手机上。如果此时我们要更新一个新的功能,如果没有热更新,那么需要用户卸载掉手机上的游戏,然后安装新的包,这样做十分麻烦,而且容易流失用户。这个时候就需要使用热更新技术,让用户在手机上下载新的游戏功能,不用重新下载就行了。下面使用的AssetBundle,严格意义上来说不算是热更新,但是,它也能减少初始包体的大小。比如我们开发一款棋牌游戏,最初的包体只放出了斗地主,在游戏中,如果玩家还想玩麻将,那么此时再下载麻将的相关资源。
AssetBundle的定义和作用:
1,AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至整个场景,可以在游戏运行的时候被加载;
2,AssetBundle自身保存着互相的依赖关系;
3,压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网络传输;
4,把一些可以下载内容放在AssetBundle里面,可以减少安装包的大小;
什么是AssetBundle:
1,它是一个存在于硬盘上的文件。可以称之为压缩包。这个压缩包可以认为是一个文件夹,里面包含了多个文件。这些文件可以分为两类:serialized file 和 resource files。(序列化文件和源文件)
serialized file:资源被打碎放在一个对象中,最后统一被写进一个单独的文件(只有一个)
resource files:某些二进制资源(图片、声音)被单独保存,方便快速加载
2,它是一个AssetBundle对象,我们可以通过代码从一个特定的压缩包加载出来的对象。这个对象包含了所有我们当初添加到这个压缩包里面的内容,我们可以通过这个对象加载出来使用。
AssetBundle使用流程图
打包成AsserBundle,放到服务器
玩家用到相应的功能,再从服务器下载
AssetBundle使用流程
1,指定资源的AssetBundle属性
2,构建AssetBundle包
3,上传AB包
4,加载AB包和包里面的资源
实际使用:
1:首先我们随便做一个需要打包的资源,然后指定该资源的AssetBundle属性。其中包名是需要指定的,后缀名可以随便写,在学习的过程中没有什么实际作用,在实际工作中根据公司需要来写吧。
注意:如果包名写成aaa,那么会直接创建以aaa为名的包。如果包名写成aaa/bbb,那么会创建名为aaa的文件夹,在此文件夹下创建名为bbb的包
2:打包之前,我们要明白,打包只是在Edidor模式下运行,在游戏运行过程中没有这个步骤。所以,创建一个文件夹名为“Editor”,特别注意只能为这个名字,然后在此文件夹下写代码来打包AssetBundle。在代码中写好方法后,将此方法放到Unity的菜单下来手动调用。
using UnityEditor;
using System.IO;
public class CreateAssetBundles {
[MenuItem("Assets/Build AssetBundles")]
static void BuildAllAssetBundles()
{
string dir = "AssetBundles";
if(Directory.Exists(dir) == false)
{
Directory.CreateDirectory(dir);
}
// BuildPipeline.BuildAssetBundles:打包的方法
// 参数:打包的路径,Build的选项(下面专门说),打包的目标平台
BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
}
}
3:在Unity菜单下,点击该选项,进行打包,打包好后资源就存在了
加载AB包和包里的资源:
我们将场景中打包用到的资源都删除,因为我们这些资源已经打包好了,可以直接加载这些资源。
注意:在加载资源的时候填入的名字,和包的名字可能不一样,要看自己创建模型的时候是取得什么名字
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LoadFromFile : MonoBehaviour {
void Start () {
// 加载ab包
AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/wood.unity3d");
// 加载资源
GameObject wallPrefab = ab.LoadAsset<GameObject>("Wood");
Instantiate(wallPrefab);
}
}
可以看到,运行后也加载好了资源
AssetBundle分组策略(仅供参考)
1,逻辑实体分组
a,一个UI界面或者所有UI界面一个包(这个界面里面的贴图和布局信息一个包)
b,一个角色或者所有角色一个包(这个角色里面的模型和动画一个包)
c,所有的场景所共享的部分一个包(包括贴图和模型)
2,按照类型分组
所有声音资源打成一个包,所有shader打成一个包,所有模型打成一个包,所有材质打成一个包
3,按照使用分组
把在某一时间内使用的所有资源打成一个包。可以按照关卡分,一个关卡所需要的所有资源包括角色、贴图、声音等打成一个包。也可以按照场景分,一个场景所需要的资源一个包
总结:
1,把经常更新的资源放在一个单独的包里面,跟不经常更新的包分离
2,把需要同时加载的资源放在一个包里面
3,可以把其他包共享的资源放在一个单独的包里面 (依赖打包)
4,把一些需要同时加载的小资源打包成一个包
5,如果对于一个同一个资源有两个版本,可以考虑通过后缀来区分
依赖打包:
如果我们有一份图片资源,有两个物体同时用到了这份资源,当单独对这两个物体进行打包的时候,打出的包中都会包含图片资源。但是当我们首先对图片资源进行打包后,再对两个物体进行打包,在打包的时候,引擎会自动检索依赖,这个时候检测到自身所依赖的图片资源已经打包了,那么这个时候自身就不会再对这个图片资源进行打包。这样,就减少了包体的大小。注意:在使用依赖打包后,如果A依赖了B的资源,那么在使用A的时候,必须加载B,否则A实例化出来后材质会丢失。
打包选项(AssetBundle压缩方式)
在上面打包的时候函数有3个参数,其中第二个参数就是打包选项,用来控制打包时的压缩方式。
1:BuildAssetBundleOptions.None:使用LZMA算法压缩,压缩的包更小,但是加载时间更长。使用之前需要整体解压。一旦被解压,这个包会使用LZ4重新压缩。使用资源的时候不需要整体解压。在下载的时候可以使用LZMA算法,一旦它被下载了之后,它会使用LZ4算法保存到本地上。
2:BuildAssetBundleOptions.UncompressedAssetBundle:不压缩,包大,加载快
3:BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4压缩,压缩率没有LZMA高,但是我们可以加载指定资源而不用解压全部
注意:使用LZ4压缩,可以获得可以跟不压缩想媲美的加载速度,而且比不压缩文件要小。
AssetBundles的使用
1,AssetBundle.LoadFromMemoryAsync :从内存加载(异步加载)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class LoadFromFile : MonoBehaviour {
IEnumerator Start () {
string path = "AssetBundles/wood.unity3d";
// 第一种加载AB的方式 LoadFromMemoryAsync
AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
yield return request;
AssetBundle ab = request.assetBundle;
// 加载资源
GameObject wallPrefab = ab.LoadAsset<GameObject>("Wood");
Instantiate(wallPrefab);
}
}
另一种写法:(同步加载)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class LoadFromFile : MonoBehaviour {
void Start () {
string path = "AssetBundles/wood.unity3d";
// 第一种加载AB的方式 LoadFromMemoryAsync
AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(path));
// 加载资源
GameObject wallPrefab = ab.LoadAsset<GameObject>("Wood");
Instantiate(wallPrefab);
}
}
注意:我们上面保存到本地,所以最好直接用文件加载。演示从内存加载的时候,我们首先把本地文件转成字节流后再加载,在实际工作中不需要多这一步,怎么合适怎么做。
2,AssetBundle.LoadFromFile :从文件加载
下面是异步加载,同步加载在最上面开始的时候就写过了
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class LoadFromFile : MonoBehaviour {
IEnumerator Start () {
string path = "AssetBundles/wood.unity3d";
// 第二种加载AB的方式 LoadFromFile
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);
yield return request;
AssetBundle ab = request.assetBundle;
// 加载资源
GameObject wallPrefab = ab.LoadAsset<GameObject>("Wood");
Instantiate(wallPrefab);
}
}
3,WWW.LoadFromCacheOrDownload (在unity2017后已废弃,分成2和4)
从本地加载
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class LoadFromFile : MonoBehaviour {
IEnumerator Start () {
string path = "AssetBundles/wood.unity3d";
//第三种加载AB的方式 WWW
while (Caching.ready == false)
{
yield return null;
}
//file:// file:///
WWW www = WWW.LoadFromCacheOrDownload(@"file:/H:\Unity Project WorkSpace\AssetBundleProject\39_AssetBundle\AssetBundles\wood.unity3d", 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>("Wood");
Instantiate(wallPrefab);
}
}
从服务器加载:这里用的是本地服务器,本地服务器使用“NetBox2.exe”双击创建
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class LoadFromFile : MonoBehaviour {
IEnumerator Start () {
string path = "AssetBundles/wood.unity3d";
//第三种加载AB的方式 WWW
while (Caching.ready == false)
{
yield return null;
}
//file:// file:///
WWW www = WWW.LoadFromCacheOrDownload(@"http://localhost/AssetBundles/wood.unity3d", 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>("Wood");
Instantiate(wallPrefab);
}
}
4,UnityWebRequest:从服务器加载
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEngine.Networking;
public class LoadFromFile : MonoBehaviour {
IEnumerator Start () {
//第四种方式 使用UnityWebRequest
// 下面2个一个从本地,一个从服务器
//string uri = @"file:///E:\Unity Project Workspace\AssetBundleProject\AssetBundles\cubewall.unity3d";
string uri = @"http://localhost/AssetBundles/cubewall.unity3d";
UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri);
yield return request.Send();
// 下面两种方式都行
//AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
// 加载资源
GameObject wallPrefab = ab.LoadAsset<GameObject>("Wood");
Instantiate(wallPrefab);
}
}
以上只是简单的使用方法,更多的使用方法需要看官方手册!!!
Unity热更新 AssetBundle的更多相关文章
- unity热更新AssetBundle框架设计_框架篇
目录 第1 章 : AssetBundle框架整体设计 课时1:实战项目开发AB技术问题分析 10:53 课时2:实战项目开发AB技术解决方案 10:24 课时3:AB框架整体设计方案详解 09:45 ...
- unity热更新方案对比
Unity应用的iOS热更新 • 什么是热更新 • 为何要热更新 • 怎样在iOS 上对Unity 应用进行热更新 • 支持Unity iOS 热更新的各种Lua 插件的对照 什么是热更新 • ...
- 另类Unity热更新大法:代码注入式补丁热更新
对老项目进行热更新 项目用纯C#开发的? 眼看Unity引擎热火朝天,无数程序猿加入到了Unity开发的大本营. 一些老项目,在当时ulua/slua还不如今天那样的成熟,因此他们选择了全c#开发:也 ...
- Unity热更新对比
https://www.jianshu.com/p/f9d90edf4a7c Unity 热更新为啥用Lua 详解 ILRuntime的优势 同市面上的其他热更方案相比,ILRuntime主要有以下优 ...
- Unity热更新技术整理
一.热更新学习介绍 1.什么是热更新 举例来说: 游戏上线后,玩家下载第一个版本(70M左右或者更大),在运营的过程中,如果需要更换UI显示,或者修改游戏的逻辑,这个时候,如果不使用热更新,就需要重新 ...
- 【转】unity 热更新思路和实现
声明:本文介绍的热更新方案是我在网上搜索到的,然后自己修改了一下,相当于是借鉴了别人的思路,加工成了自己的,在此感谢无私分享经验的朋友们. 想要使用热更新技术,需要规划设计好资源比较策略,资源版本,确 ...
- [Unity热更新]tolua# & LuaFramework(一):基础
一.tolua# c#调用lua:LuaState[变量名/函数名] 1.LuaState a.执行lua代码段 DoString(string) DoFile(.lua文件名) Require(.l ...
- Unity 热更新实例一、C#Light 和UI系统使用实例
接下来我会运用热更新的机制,逐步制作一些例子来阐释脚本系统如何和Unity结合. 脚本不限于使用C#Lite,但是C#Lite会有一些便利之处,请往下看. 结合机制也不限于这一种,但是C#Lite的设 ...
- Unity热更新 xLua
xLua是Unity3D下Lua编程解决方案,自2016年初推广以来,已经应用于十多款腾讯自研游戏,因其良好性能.易用性.扩展性而广受好评.现在,腾讯已经将xLua开源到GitHub. 2016年12 ...
随机推荐
- 【HDU5952】Counting Cliques
题目大意:给定一个\(N\)个点,\(M\)条边的无向图,求图中有多少个大小为\(S\)的团.\(N \le 100,deg(i)\le 20,i\in [1,n]\). 题解: 考虑搜索. 需要确定 ...
- mysql 表字段与关键字相同的话
desc is a reserved keyword (short for DESCENDING in ORDER BY). Enlose it into backticks: INSERT INTO ...
- qt 启动参数 -qws
运行嵌入式程序 在嵌入式QT版本中,程序需要服务器或自己作为服务器程序. 服务器程序构造的方法是构造一个QApplication::GuiServe类型的QApplication对象.或者使用-qws ...
- Maven 配置问题 - could not find resource mybatis-config.xml
需要在pom中加入以下代码 <build> <resources> <resource> <directory>src/main/resources&l ...
- 题解 [51nod1673] 树有几多愁
题面 解析 这题思路挺秒啊. 本麻瓜终于找了道好题了(还成功把ztlztl大仙拖下水了) 看到叶子节点数<=20就应该是状压啊. 然而DP要怎么写啊? 首先,考虑到编号肯定是从下往上一次增大的, ...
- Educational Codeforces Round 33 (Rated for Div. 2) A题
A. Chess For Three Alex, Bob and Carl will soon participate in a team chess tournament. Since they a ...
- whoami/who/w/last/lastlog/users/finger
whoami 显示当前有效的用户名称,相当于执行id -un命令 who 显示目前登录系统的用户信息 w 显示已经登陆系统的用户列表,并显示用户正在执行的指令 last 显示登入系统的用户 lastl ...
- Python 通过文件名批量移动文件
Python 通过文件名批量移动文件 https://stackoverflow.com/questions/28913088/moving-files-with-wildcards-in-pytho ...
- ACM之路(15)—— 字典树入门练习
刷的一套字典树的题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=120748#overview 个人喜欢指针的字典树写法,但是大力 ...
- 微信公众号【黄小斜】和【Java技术江湖】