AssetBundles (Pro only)
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 by your application. This allows you to stream in content, such as models, textures, audio clips, or even entire scenes separately from the scene in which they will be used. AssetBundles have been designed to simplify downloading content to your application.
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, they should have the extension ".bytes". Unity will import these files as TextAssets.
For some sample code showing how to use asset bundles, see the AssetBundles Example Project
Building AssetBundles
There are three class methods you can use to build AssetBundles:
- BuildPipeline.BuildAssetBundle allows you to build AssetBundles of any type of asset.
- BuildPipeline.BuildStreamedSceneAssetBundle is used when you want to include only scenes to be streamed and loaded as the data becomes available.
- BuildPipeline.BuildAssetBundleExplicitAssetNames is the same as BuildPipeline.BuildAssetBundle but has an extra parameter to specify a custom string identifier (name) for each object.
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:
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; }
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 has a version that is lower than the one requested. Otherwise the AssetBundle will be loaded from cache.
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.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.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.LoadAll will load all the objects contained in your AssetBundle. As with AssetBundle.Load, you can optionally filter objects by their type.
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.
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 to hold the names of the assets in the AssetBundle.
Instantiating objects from AssetBundles
Once you have loaded an object from your AssetBundle, you can instantiate it in your scene with the Instantiate function.
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 GameObject 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.
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.
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.
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 corresponding BuildPipeline.PopAssetDependencies function. The push and pop calls need to be balanced including the initial push that happens before building.
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.
Note that if you anticipate needing to rebuild asset bundles that are part of a dependency chain then you should build them with the BuildAssetBundleOptions.DeterministicAssetBundle option enabled. This guarantees that the internal ID values used to identify assets will be the same each time the bundle is rebuilt.
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.
Will an Asset Bundle built now be usable with future versions of Unity?
Asset bundles can contain a structure called a type tree which allows information about asset types to be understood correctly between different versions of Unity. On desktop platforms, the type tree is included by default but can be disabled by passing the BuildAssetBundleOptions.DisableWriteTypeTree to the BuildAssetBundle function. Webplayers intrinsically rely on the type tree and so it is always included (ie, the DisableWriteTypeTree option has no effect). Type trees are never included for mobile and console asset bundles and so you will need to rebuild these bundles for each new version of Unity.
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 with 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.
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 |
For example, a bundle created while the Webplayer build target was active would be compatible with the editor and with standalone builds. However, it would not be compatible with apps built for the iOS or Android platforms.
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.
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.
string url = "http://www.mywebsite.com/mygame/assetbundles/assetbundle1.unity3d"; IEnumerator Start () { // Start a download of the encrypted assetbundle WWW www = new WWW (url); // Wait for download to complete yield return www; // Get the byte data byte[] encryptedData = www.bytes; // Decrypt the AssetBundle data byte[] decryptedData = YourDecryptionMethod(encryptedData); // Create an AssetBundle from the bytes array AssetBundle bundle = AssetBundle.CreateFromMemory(decryptedData); // You can now use your AssetBundle }Page last updated: 2012-04-26