Unity热更新 AssetBundle

摘要:
下面使用的AssetBundle,严格意义上来说不算是热更新,但是,它也能减少初始包体的大小。所以,创建一个文件夹名为“Editor”,特别注意只能为这个名字,然后在此文件夹下写代码来打包AssetBundle。打包选项在上面打包的时候函数有3个参数,其中第二个参数就是打包选项,用来控制打包时的压缩方式。

在游戏开发中,常常需要用到热更新技术。比如:一个手机游戏开发好后,用户安装到手机上。如果此时我们要更新一个新的功能,如果没有热更新,那么需要用户卸载掉手机上的游戏,然后安装新的包,这样做十分麻烦,而且容易流失用户。这个时候就需要使用热更新技术,让用户在手机上下载新的游戏功能,不用重新下载就行了。下面使用的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,放到服务器

Unity热更新 AssetBundle第1张

玩家用到相应的功能,再从服务器下载

Unity热更新 AssetBundle第2张

AssetBundle使用流程

1,指定资源的AssetBundle属性

2,构建AssetBundle包

3,上传AB包

4,加载AB包和包里面的资源

实际使用:

1:首先我们随便做一个需要打包的资源,然后指定该资源的AssetBundle属性。其中包名是需要指定的,后缀名可以随便写,在学习的过程中没有什么实际作用,在实际工作中根据公司需要来写吧。

注意:如果包名写成aaa,那么会直接创建以aaa为名的包。如果包名写成aaa/bbb,那么会创建名为aaa的文件夹,在此文件夹下创建名为bbb的包

Unity热更新 AssetBundle第3张

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菜单下,点击该选项,进行打包,打包好后资源就存在了

Unity热更新 AssetBundle第4张

Unity热更新 AssetBundle第5张

加载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);
	}
}

可以看到,运行后也加载好了资源

Unity热更新 AssetBundle第6张

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算法保存到本地上。

Unity热更新 AssetBundle第7张

2:BuildAssetBundleOptions.UncompressedAssetBundle:不压缩,包大,加载快

Unity热更新 AssetBundle第8张

3:BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4压缩,压缩率没有LZMA高,但是我们可以加载指定资源而不用解压全部

Unity热更新 AssetBundle第9张

注意:使用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 WorkSpaceAssetBundleProject39_AssetBundleAssetBundleswood.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 WorkspaceAssetBundleProjectAssetBundlescubewall.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》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇初识Git(一)log file sync 因为数据线有问题而造成高等侍的表现下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

教你高速高效接入SDK——Unity统一接入渠道SDK(Android篇)

U8SDK的设计之初,就是为了可以支持各种游戏引擎开发的游戏,而不不过Android的原生平台。眼下一大半的手游,都是採用Unity3D和Cocos2dx开发,那么这里,我们就先来一步步给大家演示,用Unity开发的游戏,怎样通过U8SDK来高速地完毕多家渠道SDK的接入。 Unity研发的手游,仅仅须要调用U8SDK抽象层就可以完毕多家渠道SDK的接...

Unity打开外部程序exe/Bat文件方案

Unity调用外部程序/Bat文件 本文提供全流程,中文翻译。 Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) Chinar —— 心分享、心创新!助力完成 Unity 打开外部程序 exe / bat 文件为新手节省宝贵的时间,避免采坑! Chinar 教程效果:...

UFPS入门: Unity FPS 教程

http://blog.csdn.net/kmyhy/article/details/72846348 UFPS : Ultimate FPS v1.7.3  download:https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.11891deb83c0WO&id=57129885...

【Unity插件】NGUI核心组件之UIPanel .

转自:http://blog.csdn.net/daiguangda/article/details/7840084   UIPanel负责创建实际的集合图形。你不需要手动的添加UIPanel-一旦你创建一个控件,它会自动被添加。如果你想将你的UI渲染拆分到不同的Draw Call中,你可以手动创建你自己的UIPanel,例如你要创建一个分屏的游戏,每个屏...

Unity3D 物体移动方法总结

1. 简介     在Unity3D中,有多种方式可以改变物体的坐标,实现移动的目的,其本质是每帧修改物体的position。 2. 通过Transform组件移动物体     Transform 组件用于描述物体在空间中的状态,它包括 位置(position), 旋转(rotation)和 缩放(scale)。 其实所有的移动都会导致position的改...

Unity2019使用Android Studio 4出安卓包

前言 在我所经历的项目组中有这几种方法来生成APK 直接在Unity生成APK,可以接入SDK 使用Unity导出Android Studio工程手动生成APK 使用Unity导出Android Studio工程命令行离线生成APK 这里记录一下我在项目组使用Android Studio出包的笔记。 使用Unity导出Android Studio工程前...