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.

在一些大型的網絡游戲,或者加載比較多的一些場景時,如果要等待所有模型,貼圖等各種資源文件加載完畢才能執行游戲,對用戶將會是一個很頭大的事情。所以就需要用到動態加載,即AssetBundles。比如玩家在進入游戲時先加載一些周圍的場景文件,這樣不僅可以提高速度還可以減少內存資源的消耗。

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

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..

有三個類方法可以用來構建資源包: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,允許用戶自動包含與之相關的或者總是包含完整的資源去代替確切的參照物體。】

當使用上面的三個函數做完准備工作,我們現在就需要去下載這些資源然后加載它們。

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";IEnumeratorStart(){// Start a download of the given URL// 從指定路徑下載 WWW www = WWW.LoadFromCacheOrDownload(url,1);// Wait for download to complete// 等待下載完成yieldreturn www;// Load and retrieve the AssetBundle// 加載並取回資源包AssetBundle bundle = www.assetBundle;}

 

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";IEnumeratorStart(){// Start a download of the given URL// 開始從指定路徑下載 WWW www = WWW.LoadFromCacheOrDownload(url,1);// Wait for download to complete// 等待下載完成yieldreturn www;// Load and retrieve the AssetBundle// 加載並取回資源包AssetBundle bundle = www.assetBundle;// Load the TextAsset object// 加載文本資源對象GameObject go = bundle.Load("myGameObject",typeof(GameObject))asGameObject;// 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";IEnumeratorStart(){// Start a download of the given URL WWW www = WWW.LoadFromCacheOrDownload(url,1);// Wait for download to completeyieldreturn www;// Load and retrieve the AssetBundleAssetBundle bundle = www.assetBundle;// Load the TextAsset objectTextAsset txt = bundle.Load("myBinaryAsText",typeof(TextAsset))asTextAsset;// Retrieve the binary data as an array of bytesbyte[] 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";IEnumeratorStart(){// Start a download of the given URL WWW www = WWW.LoadFromCacheOrDownload(url,1);// Wait for download to completeyieldreturn www;// Load and retrieve the AssetBundleAssetBundle bundle = www.assetBundle;// Load the TextAsset objectTextAsset txt = bundle.Load("myBinaryAsText",typeof(TextAsset))asTextAsset;// Load the assembly and get a type (class) from itvar assembly =System.Reflection.Assembly.Load(txt.bytes);var type = assembly.GetType("MyClassDerivedFromMonoBehaviour");// Instantiate a GameObject and add a component with the loaded classGameObject go =newGameObject(); 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方法來異步加載對象,這樣一來可以減少在應用程序中被打斷的可能性。

 

usingUnityEngine;IEnumeratorStart(){// Start a download of the given URL WWW www = WWW.LoadFromCacheOrDownload(url,1);// Wait for download to completeyieldreturn www;// Load and retrieve the AssetBundleAssetBundle bundle = www.assetBundle;// Load the object asynchronouslyAssetBundleRequest request = bundle.LoadAsync("myObject",typeof(GameObject));// Wait for completionyieldreturn request;// Get the reference to the loaded objectGameObject obj = request.asset asGameObject;}

 

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";IEnumeratorStart(){// Start a download of the given URL WWW www =new WWW (url);// Wait for download to completeyieldreturn www;// Get the byte databyte[] encryptedData = www.bytes;// Load the TextAsset objectbyte[] decryptedData =YourDecryptionMethod(encryptedData);// Create an AssetBundle from the bytes arrayAssetBundle bundle =AssetBundle.CreateFromMemory(decryptedData);// You can now use your AssetBundle}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM