Hay dos pasos principales involucrados cuando trabaje con AssetBundles. El primer paso es descargar el AssetBundle desde un servidor o una ubicación en disco. Esto se realiza a través de la clase WWW. El segundo paso es cargar los Assets desde el AssetBundle, en ser utilizados en la aplicación. Aquí hay un ejemplo de un script en C# de esto:
using UnityEngine;
using System.Collections;
public class BundleLoader : MonoBehaviour{
public string url;
public int version;
public IEnumerator LoadBundle(){
while (!Caching.ready)
yield return null;
using(WWW www = WWW.LoadFromCacheOrDownload(url, version)) {
yield return www;
AssetBundle assetBundle = www.assetBundle;
GameObject gameObject = assetBundle.mainAsset as GameObject;
Instantiate(gameObject);
assetBundle.Unload(false);
}
}
void Start(){
StartCoroutine(LoadBundle());
}
}
Este script es agregado al GameObject como Componente. El AssetBundle es cargado en la siguiente manera:
Por favor tenga en cuenta que por simplicidad el ejemplo previo no está haciendo ninguna revisión de seguridad. Por favor ver el código aquí para un ejemplo más complejo.
Como crear aplicaciones es un proceso iterativo, usted seguramente va a modificar sus Assets muchas veces, lo cual requeriría que se re-construyan los AssetBundles después de cada cambio para ser capaz de probarlos. Aunque sea posible cargar AssetBundles en el Editor, este no es flujo de trabajo recomendado. Más bien, mientras pruebe en el Editor, usted debería utilizar la función de ayuda Resources.LoadAssetAtPath para evitar que tenga que utilizar y re-construir AssetBundles. La función le permite a usted cargar el Asset como si fuera cargado desde un AssetBundle, mientras omite el proceso de construcción y sus Assets siempre están actualizados.
Lo siguiente es un ejemplo de un script de ayuda, que usted puede utilizar para cargar sus Assets dependiendo si usted está corriendo en el Editor o no. Coloque este código en un script C# llamado AssetBundleLoader.cs:
using UnityEngine;
using System.Collections;
public class AssetBundleLoader {
public Object Obj; // The object retrieved from the AssetBundle
public IEnumerator LoadBundle<T> (string url, int version, string assetName, string assetPath) where T : Object {
Obj = null;
#if UNITY_EDITOR
Obj = Resources.LoadAssetAtPath(assetPath, typeof(T));
if (Obj == null)
Debug.LogError ("Asset not found at path: " + assetPath);
yield break;
#else
WWW download;
if ( Caching.enabled ) {
while (!Caching.ready)
yield return null;
download = WWW.LoadFromCacheOrDownload( url, version );
}
else {
download = new WWW (url);
}
yield return download;
if ( download.error != null ) {
Debug.LogError( download.error );
download.Dispose();
yield break;
}
AssetBundle assetBundle = download.assetBundle;
download.Dispose();
download = null;
if (assetName == "" || assetName == null)
Obj = assetBundle.mainAsset;
else
Obj = assetBundle.Load(assetName, typeof(T));
assetBundle.Unload(false);
#endif
}
}
Ahora nosotros podemos utilizar el script AssetBundleLoader para cargar un Asset desde un AssetBundle si estamos corriendo la aplicación construida o cargar el Asset directamente desde la carpeta del Proyecto si está corriendo en el Editor:
using UnityEngine;
using System.Collections;
public class ExampleLoadingBundle : MonoBehaviour {
public string url = "http://www.mygame.com/myBundle.unity3d"; // URL where the AssetBundle is
public int version = 1; // The version of the AssetBundle
public string assetName = "MyPrefab"; // Name of the Asset to be loaded from the AssetBundle
public string assetPath; // Path to the Asset in the Project folder
private Object ObjInstance; // Instance of the object
void Start(){
StartCoroutine(Download());
}
IEnumerator Download () {
AssetBundleLoader assetBundleLoader = new AssetBundleLoader ();
yield return StartCoroutine(assetBundleLoader.LoadBundle <GameObject> (url, version, assetName, assetPath));
if (assetBundleLoader.Obj != null)
ObjInstance = Instantiate (assetBundleLoader.Obj);
}
void OnGUI(){
GUILayout.Label (ObjInstance ? ObjInstance.name + " instantiated" : "");
}
}
El script previo debería ser guardado a un archivo llamado ExampleLoadingBundle.cs dentro de la carpeta de Assets. Después de configurar las variables públicas a sus valores correctos y correrlas, se va a utilizar la clase AssetBundleLoader para cargar un Asset. Luego es instanciado y esto será mostrado al utilizar el GUI.
Se puede utilizar WWW.LoadFromCacheOrDownload el cual automáticamente se ocupa de guardas sus AssetBundles en disco. Es posible comprar una licencia para almacenar en caché por separado para su juego si se requiere más espacio.
Si sus AssetBundles están almacenados en la carpeta StreamingAssets como AssetBundles descomprimidos, usted puede utilizar AssetBundle.CreateFromFile para referenciar el AssetBundle en disco. Si los AssetBundles en la carpeta StreamingAssets están comprimidos, usted va a necesitar utilizar WWW.LoadFromCacheOrDownload para crear una copia descomprimida del AssetBundle en caché.
Los AssetBundles son compatibles entre algunas plataformas. Utilice la siguiente tabla como una guía.
Compatibilidad de plataforma para AssetBundles | |||
Standalone | iOS | Android | |
Editor | Y | Y* | Y* |
Standalone | Y | ||
iOS | Y | ||
Android | Y |
(*) AssetBundles built for mobile platforms might contain data stored in an optimized, platform-specific format which is incompatible with the platform the Editor is running on. Note that it is safe to assume that published games needs different asset bundles per platform. Specifically shaders are different between platforms.
E.g. GI data is stored in a format optimized for ARM architecture and thus is not loadable on x86 CPUs. Shaders are stored for OpenGLES 2 configuration and are not loadable by the Editor which uses the DX9/11 renderer (but works with OpenGLCore renderer). During development, you are recommended to use Simulation Mode mentioned in AssetBundles and the AssetBundle Manager tutorial to avoid Editor and mobile platforms incompatibility.
Cuando usted construya AssetBundles los assets son identificados internamente por su nombre de archivo sin la extensión. Por ejemplo, una Textura ubicada en la carpeta Project en “Assets/Textures/myTexture.jpg” es identificada y cargada utilizando “myTexture” si usted utiliza el método por defecto. Usted puede tener más control sobre esto al proporcionar su propio arreglo de ids (strings) para cada objecto cuando construya su AssetBundle con BuildPipeline.BuildAssetBundleExplicitAssetNames.
Los AssetBundles le permiten a usted compartir contenido entre diferentes juegos. El requerimiento is que cualquier assets que sea referenciado por GameObjects en su AssetBundle debe ser incluido en el AssetBundle. Para asegurarse que los assets referenciados sean incluidos en el AssetBundle cuando son construidos usted puede pasar la opción BuildAssetBundleOptions.CollectDependencies.
Los AssetBundles pueden contener una estructura llamada un type tree que permite información acerca de los tipos de assets para entender correctamente entre diferentes versiones de Unity. En plataformas de escritorio, el type tree es incluido por defecto pero puede desactivarse al pasar BuildAssetBundleOptions.DisableWriteTypeTree a la función BuildAssetBundle. Los Webplayers intrinsecamente dependen en el type tree por lo que siempre son incluido (ie, la opción DisableWriteTypeTree no tiene efecto). Type trees nunca son incluidos para los assetbundles móviles o de consola y por lo tanto usted necesitará re-construir estos bundles cuando el formato de serialización cambie. Esto puede suceder en nuevas versiones de Unity. (Excepto para lanzamientos de arreglos a bugs) También sucede si usted agrega o quita campos serializados en monobehaviour que son incluidos en el assetbundle. Cuando cargue un AssetBundle, Unity va a intentar darle un mensaje de error si el AssetBundle debe ser re-construido.
Usted puede utilizar AssetBundle.LoadAllAssets para recuperar un arreglo que contenga todos los objetos del AssetBundle. No es posible obtener una lista de los identificados directamente. Una solución alternativa común es mantener un TextAsset (asset de texto) separado para mantener los nombres de los assets en el AssetBundle.
Suponga que el Bundle A contiene un Prefab que tiene un material y una textura. Bundle B tiene una escena que tiene una instancia del mismo prefab. Bundle B necesita acceder al material. Al menos de que el material sea incluido en un asset bundle específico, será incluido en ambos bundle A y B.