【轉】Unity3D AssetBundles 動態加載遊戲資源

AssetBundles are files which you can export from Unity to contain assets of your choice. These files use a proprietary compressed format and can be loaded on demand in your application. This allows you to stream content like models, textures, audio clips and even entire scenes separately from the scene in which they will be used. They have been designed to make it easy to download content to your application. html

在一些大型的網絡遊戲,或者加載比較多的一些場景時,若是要等待全部模型,貼圖等各類資源文件加載完畢才能執行遊戲,對用戶將會是一個很頭大的事情。因此就須要用到動態加載,即AssetBundles。好比玩家在進入遊戲時先加載一些周圍的場景文件,這樣不只能夠提升速度還能夠減小內存資源的消耗。 node

AssetBundles是能夠把unity3d中你所建立的文件或任何資源導出的一種文件格式,這些文件導出後使用的是一種特定的文件格式(.Unity3d),這些特定格式的文件能在須要的時候加載到場景中。而這些特定的文件格式能夠是模型,貼圖,聲音文件甚至是場景文件,它們是先前就被設計好的文件,因此很容易就能夠被下載到你所創建的遊戲或場景中來。 web

AssetBundles can contain any kind of asset type recognized by Unity, as determined by the filename extension. If you want to include files with custom binary data, then you must rename those files to have ".bytes" as the extension. Unity will import these files as TextAssets. 數組

AssetBundles 能夠是任意類型的文件只要是unity3d能識別的資源文件格式,識別主要是以文件擴展名爲準,好比.prefab等等。固然若是你想包含自定義的二進制文件,須要命名這些文件爲以".bytes"爲後綴,Unity將會把這些文件導成TextAssets。 緩存

For some sample code showing how to use asset bundles, see the AssetBundles Example Project 安全

若是想了解更多關於代碼如何實現,能夠參考 AssetBundles Example Project網絡

Creating AssetBundles 建立資源包

There are three class methods you can use to build AssetBundles: BuildPipeline.BuildAssetBundleBuildPipeline.BuildStreamedSceneAssetBundleand BuildPipeline.BuildAssetBundleExplicitAssetNames.. app

有三個類方法能夠用來構建資源包:BuildPipeline.BuildAssetBundleBuildPipeline.BuildStreamedSceneAssetBundle 和BuildPipeline.BuildAssetBundleExplicitAssetNames. 異步

  • BuildPipeline.BuildAssetBundle allows you to build AssetBundles of any type of asset. 
    能夠構建任意類型資源的資源包。【建立一個壓縮好的包含Assets下的全部資源文件.unity3d。能夠包含是項目目錄下的任意資源,而把全部的資源壓縮成一個.unity3d的文件,這個文件包括全部的預置物體(prefabs),紋理貼圖(textures),模型,動畫。使用AssetBundle.mainAsset這個函數能夠很方便的讓你指定一個定義好的物體。被壓縮的資源儲存在pathName. Options,會自動的容許用戶包含相關的或者須要用到的】
  • BuildPipeline.BuildStreamedSceneAssetBundle is used when you want to include only scenes to be streamed and loaded as the data becomes available. 
    用來當你但願只包括流場景,使數據加載變爲可用。【創建一個或多個場景,這些場景所須要的全部資源將被壓縮入資源包,即asset bundle裏面。資源包中的場景文件能夠在任何平臺上創建,並且這些文件每每是以一個單一的unity3d文件格式被用來建立。使用WWW類能夠下載場景文件。當場景文件被下載好可使用WWW.LoadFromCacheOrDownload來加載下載好的場景文件。】
  • BuildPipeline.BuildAssetBundleExplicitAssetNames is the same as BuildPipeline.BuildAssetBundle but has an extra parameter to specify a custom string identifier (name) for each object. 
    和BuildPipeline.BuildAssetBundle相似,可是有額外的參數來指定每一個物體的自定義的字符串(名字)。【創建一個自定義名字的資源包方法: 建立一個包含全部資源的一個壓縮好的unity3d文件。AssetBundle能夠包括任何項目目錄下的資源文件。在assetNames參數中提供一個與資源數目相同大小的字符串數組。在資源數組中存儲的信息與資源文件名相同,能夠傳遞AssetBundle.Load去加載一個指定的資源。使用BuildAssetBundle時,只需使用資源的路徑名。壓縮好的資源包文件將會被儲存在pathName. Options,容許用戶自動包含與之相關的或者老是包含完整的資源去代替確切的參照物體。】

當使用上面的三個函數作完準備工做,咱們如今就須要去下載這些資源而後加載它們。 async

Downloading AssetBundles 下載資源包

The recommended way to download AssetBundles is to use WWW.LoadFromCacheOrDownload. Once the download is complete you can retrieve the AssetBundle with the assetBundle property. For example:

推薦使用WWW.LoadFromCacheOrDownload方法用來下載資源。當下載完成你就能夠從新獲得該資源的相關屬性,例如:

string url = "http://www.mywebsite.com/mygame/assetbundles/assetbundle1.unity3d"; IEnumerator Start () { // Start a download of the given URL // 從指定路徑下載 WWW www = WWW.LoadFromCacheOrDownload (url, 1); // Wait for download to complete // 等待下載完成 yield return www; // Load and retrieve the AssetBundle // 加載並取回資源包 AssetBundle bundle = www.assetBundle; }

 

using UnityEngine; // Note: This example does not check for errors. Please look at the example in the DownloadingAssetBundles section for more information 
IEnumerator Start () { // Start a download of the given URL 
WWW www = WWW.LoadFromCacheOrDownload (url, 1); // Wait for download to complete 
yield return www; // Load and retrieve the AssetBundle 
AssetBundle bundle = www.assetBundle; // Load the object asynchronously 
AssetBundleRequest request = bundle.LoadAsync ("myObject", typeof(GameObject)); // Wait for completion 
yield return request; // Get the reference to the loaded object 
GameObject obj = request.asset as GameObject; // Unload the AssetBundles compressed contents to conserve memory bundle.Unload(false); }

When you access the .assetBundle property the downloaded data is extracted and the AssetBundle object is created. At this point, you are ready to load the objects contained in the bundle. The second parameter passed to LoadFromCacheOrDownload specifies which version of the AssetBundle to download. LoadFromCacheOrDownload will download the AssetBundle if it doesn't exist in the cache or if it exists but is associated with a version that is lower than the one requested. Otherwise the AssetBundle will be loaded from cache.

以上代碼中的url是資源路徑的下載地址,首先使用LoadFromCacheOrDownload下載資源,括號中的url是路徑,1表明版本號,當等待下載完成後便可加載相關資源。

當資源包中的對象建立好以後,就能夠激活下載好的資源被解壓。到這裏,就須要用戶去加載包含在資源包器中的對象。LoadFromCacheOrDownload函數中的第二個參數是指定下載資源的版本號。若是在存儲器中的資源沒有被下載或者資源下載了可是比須要資源的版本號低,LoadFromCacheOrDownload函數將會下載資源到資源包中。不然資源包其將會直接從存儲器中加載。

Loading and unloading objects from an AssetBundle 從資源包加載和卸載對象

Having created an AssetBundle object from the downloaded data, you can load the objects contained in it using three different methods:AssetBundle.LoadAssetBundle.LoadAsync and AssetBundle.LoadAll.

若是下載數據已經創建了資源包,你就可使用這三個不一樣的函數來加載物體了: AssetBundle.LoadAssetBundle.LoadAsync 和 AssetBundle.LoadAll.

  • AssetBundle.Load will load an object using its name identifier as a parameter. The name is the one visible in the Project view. You can optionally pass an object type as an argument to the Load method to make sure the object loaded is of a specific type. 
    AssetBundle.Load會加載物體,使用該物體的名字做爲識別的參數。名字能夠在Unity3d中Project view看到。你能夠自由選擇去傳遞對象變量的類型來確認該加載對象是不是被指定的類型。
  • AssetBundle.LoadAsync works the same as the Load method described above but it will not block the main thread while the asset is loaded. This is useful when loading large assets or many assets at once to avoid pauses in your application. 
    AssetBundle.LoadAsync 與AssetBundle.Load 函數相相似,可是當資源加載時它不會阻礙主線程。若是同時要加載比較大的資源或者不少資源時,這個函數會比較有用,它能夠避免程序的暫停,由於它會同步加載。
  • AssetBundle.LoadAll will load all the objects contained in your AssetBundle. As with AssetBundle.Load, you can optionally filter objects by their type. 
    AssetBundle.LoadAll 顧名思義這個函數是用來加載全部在你資源包中的對象。做爲AssetBundle.Load這個函數,你能夠隨意用該對象的類型去過濾。

To unload assets you need to use AssetBundle.Unload. This method takes a boolean parameter which tells Unity whether to unload all data (including the loaded asset objects) or only the compressed data from the downloaded bundle. If your application is using some objects from the AssetBundle and you want to free some memory you can pass false to unload the compressed data from memory. If you want to completely unload everything from the AssetBundle you should pass true which will destroy the Assets loaded from the AssetBundle.

使用AssetBundle.Unload這個函數能夠卸載加載好的資源,這個函數有一個布爾值的參數是用來告訴Unity是否要卸載全部的數據(包含加載的資源對象)或者只是已經下載過的被壓縮好的資源數據。若是要在資源包中從你的應用程序要使用一些對象或者你想釋放一些內存,能夠傳遞false這個值來卸載已經壓縮好了的文件從你的內存中(即.unity3d文件)。若是要徹底卸載全部的資源數據,須要傳遞true這個值,這將會銷燬全部的資源包器中加載的資源。

Listing objects in an AssetBundle 從資源包列表物體

You can use AssetBundle.LoadAll to retrieve an array containing all objects from the AssetBundle. It is not possible to get a list of the identifiers directly. A common workaround is to keep a separate TextAsset with a known name to hold the names of the assets in the AssetBundle.

可使用AssetBundle.LoadAll 去取回資源包中包含的全部對象的數組。不可能直接就取回一個列表。一般的作法是保持一個單獨的TextAsset,這個TextAsset是控制資源包中資源的名稱。

Instantiating objects from AssetBundles 從資源包實例化物體

Once you have loaded an object from your AssetBundle, you can instantiate it in your scene with the Instantiate function.

下載了資源,也加載好了,那麼就該在場景中使用Instantiate函數去實例化它了。

string url = "http://www.mywebsite.com/mygame/assetbundles/assetbundle1.unity3d"; IEnumerator Start () { // Start a download of the given URL // 開始從指定路徑下載 WWW www = WWW.LoadFromCacheOrDownload (url, 1); // Wait for download to complete // 等待下載完成 yield return www; // Load and retrieve the AssetBundle // 加載並取回資源包 AssetBundle bundle = www.assetBundle; // Load the TextAsset object // 加載文本資源對象 GameObject go = bundle.Load("myGameObject", typeof(GameObject)) as GameObject; // Instantiate the GameObject // 實例化該對象 Instantiate(go); }

 

Keeping track of downloaded AssetBundles 保持跟蹤下載的資源包

Unity doesn't provide an automatic way to retrieve a list of AssetBundles that have been downloaded. You can keep track of this information from a script by storing references to the AssetBundle objects and their URLs, say.

Unity不提供自動的一個能夠取回全部被下載資源的列表。因此須要咱們在腳本中要創建這些資源對象的信息和它們的路徑以便咱們去查找。

Storing and loading binary data in an AssetBundle 在資源包儲存和加載二進制數據

The first step is to save your binary data file with the ".bytes" extension. Unity will treat this file as a TextAsset. As a TextAsset the file can be included when you build your AssetBundle. Once you have downloaded the AssetBundle in your application and loaded the TextAsset object, you can use the .bytes property of the TextAsset to retrieve your binary data.

第一步要儲存文件的擴展名以" .bytes"爲結尾的二進制數據。Unity會把它們當作TextAsset來使用。當你創建資源包就會包含一個TestAsset的文件。當在資源包應用程序中下載好這個二進制數據後也須要加載它們,可使用TextAsset的.bytes的屬性去取回你的二進制數據。

string url = "http://www.mywebsite.com/mygame/assetbundles/assetbundle1.unity3d"; IEnumerator Start () { // Start a download of the given URL WWW www = WWW.LoadFromCacheOrDownload (url, 1); // Wait for download to complete yield return www; // Load and retrieve the AssetBundle AssetBundle bundle = www.assetBundle; // Load the TextAsset object TextAsset txt = bundle.Load("myBinaryAsText", typeof(TextAsset)) as TextAsset; // Retrieve the binary data as an array of bytes byte[] bytes = txt.bytes; }

 

Including scripts in AssetBundles 在資源包中包含腳本

AssetBundles can contain scripts as TextAssets but as such they will not be actual executable code. If you want to include code in your AssetBundles that can be executed in your application it needs to be pre-compiled into an assembly and loaded using the Mono Reflection class (Note: Reflection is not available on iOS). You can create your assemblies in any normal C# IDE (e.g. Monodevelop, Visual Studio) or any text editor using the mono/.net compilers.

資源包能夠做爲TextAssets包含腳本可是不會實際執行代碼。若是想要在資源包包含用來執行應用程序的代碼,須要預先編譯,而後使用Mono Reflection class來加載(注意:Reflection在iOS平臺不可用)。能夠在任何版本的C#IDE編輯器(如:Monodevelop, Visual Studio)或者使用mono/.net 文檔編輯器。

string url = "http://www.mywebsite.com/mygame/assetbundles/assetbundle1.unity3d"; IEnumerator Start () { // Start a download of the given URL WWW www = WWW.LoadFromCacheOrDownload (url, 1); // Wait for download to complete yield return www; // Load and retrieve the AssetBundle AssetBundle bundle = www.assetBundle; // Load the TextAsset object TextAsset txt = bundle.Load("myBinaryAsText", typeof(TextAsset)) as TextAsset; // Load the assembly and get a type (class) from it var assembly = System.Reflection.Assembly.Load(txt.bytes); var type = assembly.GetType("MyClassDerivedFromMonoBehaviour"); // Instantiate a GameObject and add a component with the loaded class GameObject go = new GameObject(); go.AddComponent(type); }

 

Managing asset dependencies 管理相關資源

Any given asset in a bundle may depend on other assets. For example, a model may incorporate materials which in turn make use of textures and shaders. It is possible to include all an asset's dependencies along with it in its bundle. However, several assets from different bundles may all depend on a common set of other assets (eg, several different models of buildings may use the same brick texture). If a separate copy of a shared dependency is included in each bundle that has objects using it, then redundant instances of the assets will be created when the bundles are loaded. This will result in wasted memory.

任何在資源包中給出的資源可能主要依賴於其它的資源。舉個例子,一個模型可能混合多種紋理和材質球中的材質,可能包括全部的某個資源相關的東西,然而,一些從不一樣資源包文件夾中的資源或許都要用到相同的一些其它資源(好比說一些不一樣的建築模型會用到相同的紋理貼圖)。若是在每一個資源文件夾中包含一個被共享的資源要被某個對象用到,當資源文件加載的時候那就不須要去實例化多餘的對象,換句話說就是隻要把共享的資源實例化一次就能夠了,這樣就能夠大大減小內存的佔用。

To avoid such wastage, it is possible to separate shared dependencies out into a separate bundle and simply reference them from any bundles with assets that need them. First, the referencing feature needs to be enabled with a call to BuildPipeline.PushAssetDependencies. Then, the bundle containing the referenced dependencies needs to be built. Next, another call to PushAssetDependencies should be made before building the bundles that reference the assets from the first bundle. Additional levels of dependency can be introduced using further calls to PushAssetDependencies. The levels of reference are stored on a stack, so it is possible to go back a level using the correspondingBuildPipeline.PopAssetDependencies function. The push and pop calls need to be balanced including the initial push that happens before building.

要避免資源的浪費,能夠單獨創建一個專門的文件夾用來放要被共享的資源或者全部須要被加載的對象,官方提供的AssetBundles Example Project中的AssetBundles這個文件夾就是一個不錯的選擇,要查看該文件夾須要進入unity3D->在Project中右擊會看到一個下拉菜單有Auto Build Rescources Files的選項,點擊它,而後進入AsssetBundles資源目錄下你會發現多了一個名爲AssetBundles的文件夾,全部的資源已經被轉化成.unity3d的格式存儲在這裏了。要把這些資源存儲在指定的AssetBundles這個文件夾下,須要用到BuildPipeline.PushAssetDependencies和BuildPipeline.PopAssetDependencies這兩個函數。首先須要BuildPipeline.PushAssetDependencies來激活將要使用到的資源文件夾(好比AssetBundles Example Project中的AssetBundles這個文件夾)。而後就須要創建你想在這個文件夾中存放什麼資源了,好比說一個紋理貼圖。接着再次呼叫BuildPipeline.PushAssetDependencies來激活下一個將要使用到的和先前存放資源相關的其它資源。好比說有一個角色的模型,這個角色模型有它本身的紋理貼圖,那就須要先激活它的貼圖而後激活模型自己。如此反覆直到把全部與須要加載資源的其它相關資源都使用BuildPipeline.PushAssetDependencies加載完畢,最後再使用BuildPipeline.PopAssetDependencies來告訴程序這個模型全部的相關資源已經所有加載完成。

At runtime, you need to load a bundle containing dependencies before any other bundle that references them. For example, you would need to load a bundle of shared textures before loading a separate bundle of materials that reference those textures.

在運行時,須要考慮到優先加載資源的順序。舉個例子,如今有一張紋理貼圖,這張貼圖可能被不少個模型須要用到,而這個貼圖又有不少不一樣的材質,那就得先加載紋理貼圖,而後材質,最後纔是模型。

具體的代碼實現過程可參考AssetBundles Example Project中的AutoExportRescources這個腳本。

Can I reuse my AssetBundles in another game? 
能夠在其餘的遊戲場景從新使用個人資源包嗎?

AssetBundles allow you to share content between different games. The requirement is that any Assets which are referenced by GameObjects in your AssetBundle must either be included in the AssetBundle or exist in the application (loaded in the current scene). To make sure the referenced Assets are included in the AssetBundle when they are built you can pass the BuildAssetBundleOptions.CollectDependencies option.

資源包容許用戶去共享資源包中的內容到其它不一樣的遊戲。若是須要共享,前提須要你已經創建好這個資源包共享文件。可使用BuildAssetBundleOptions.CollectDependencies這個函數來檢測是否已經創建好資源包文件。

How are assets in AssetBundles identified?
資源包中的資源如何被識別?

When you build AssetBundles the assets are identified internally by their filename without the extension. For example a Texture located in your Project folder at "Assets/Textures/myTexture.jpg" is identified and loaded using "myTexture" if you use the default method. You can have more control over this by supplying your own array of ids (strings) for each object when Building your AssetBundle withBuildPipeline.BuildAssetBundleExplicitAssetNames.

當在內部創建資源包時,它們的文件名不包含擴展名就會被識別。舉個例子,一個在你項目工程目錄下好比說"Assets/Textures/myTextures.jpg"的貼圖是用"myTexture"來識別。若是使用默認的方法,當你用BuildPipeline.BuildAssetBundleExplicitAssetNames這個函數創建你的資源包,那你能夠有不少你本身編號的數組上的控制。

Loading objects from an AssetBundles asynchronously
從資源包異步加載對象

You can use the AssetBundle.LoadAsync method to load objects Asynchronously and reduce the likelihood of having hiccups in your application.

可使用AssetBundle.LoadAsync方法來異步加載對象,這樣一來能夠減小在應用程序中被打斷的可能性。

using UnityEngine; IEnumerator Start () { // Start a download of the given URL WWW www = WWW.LoadFromCacheOrDownload (url, 1); // Wait for download to complete yield return www; // Load and retrieve the AssetBundle AssetBundle bundle = www.assetBundle; // Load the object asynchronously AssetBundleRequest request = bundle.LoadAsync ("myObject", typeof(GameObject)); // Wait for completion yield return request; // Get the reference to the loaded object GameObject obj = request.asset as GameObject; }

 

Are AssetBundles cross-platform?
資源包能夠跨平臺嗎?

AssetBundles are compatible between some platforms. Use the following table as a guideline.

在有一些平臺中是能夠兼容的,能夠參考下面的這個表格。

Platform compatibility for AssetBundles 資源包在平臺的兼容性
  Standalone Webplayer iOS Android
Editor Y Y Y Y
Standalone Y Y    
Webplayer Y Y    
iOS     Y  
Android       Y

How do I cache AssetBundles? 如何緩存資源包?

You can use WWW.LoadFromCacheOrDownload which automatically takes care of saving your AssetBundles to disk. Be aware that on the Webplayer you are limited to 50MB in total (shared between all webplayers). You can buy a separate caching license for your game if you require more space.

使用WWW.LoadFromCacheOrDownload就能夠自動在你的硬盤上存儲資源包文件。可是說明一下Webplayer被限制50MB的存儲空間。若是須要更多空間則能夠單獨爲遊戲購買緩存許可證。

Protecting content 保護內容

Unity allows you to create an AssetBundle object from a byte[] array with AssetBundle.CreateFromMemory. You can use this as a way to enhance the security by encrypting your assetbundles before transmission and decrypt them at runtime.

Unity容許用戶使用AssetBundle.CreateFromMemory從一個 byte[]數組中創建一個AssetBundle的對象。在運行時傳輸和解密以前,能夠用這種加密方法來提升安全性和保護用戶創建的資源包中內容。

string url = "http://www.mywebsite.com/mygame/assetbundles/assetbundle1.unity3d"; IEnumerator Start () { // Start a download of the given URL WWW www = new WWW (url); // Wait for download to complete yield return www; // Get the byte data byte[] encryptedData = www.bytes; // Load the TextAsset object byte[] decryptedData = YourDecryptionMethod(encryptedData); // Create an AssetBundle from the bytes array AssetBundle bundle = AssetBundle.CreateFromMemory(decryptedData); // You can now use your AssetBundle }
相關文章
相關標籤/搜索