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對象,咱們能夠經過代碼從一個特定的壓縮包加載出來的對象。這個對象包含了全部咱們當初添加到這個壓縮包裏面的內容,咱們能夠經過這個對象加載出來使用。ui

AssetBundle使用流程圖

打包成AsserBundle,放到服務器spa

 玩家用到相應的功能,再從服務器下載

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

 

以上只是簡單的使用方法,更多的使用方法須要看官方手冊!!!

相關文章
相關標籤/搜索