Incluyendo scripts en AssetBundles
Reduciendo el Tamaño del Archivo de la Construcción

AssetBundles PF (Preguntas Frecuentes)

¿Cómo uso un AssetBundle?

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:

  • El url y los valores de la versión deben ser configurados en el Inspector antes de correr este script. El url es la ubicación del archivo AssetBundle, usualmente un servidor en el internet. El número de versión le permite al desarrollador asociar un número al AssetBundle cuando sea escrito en caché en disco. Cuando descargue un AssetBundle Unity va a revisar si el archivo ya existe en el caché. Si sí, compara la versión del asset almacenado con la versión pedida. Si es diferente entonces el AssetBundle será re-descargado. Si es el mismo, entonces va a cargar el AssetBundle de disco y va a evitar que se re-descargue el archivo. Por favor referirse a la función WWW.LoadFromCacheOrDownload en la referencia de scripting para más información acerca de estos parámetros.
  • Cuando la función Start de este script es llamada, va a comenzar a cargar el AssetBundle al llamar la función como una Coroutine. La función va a esperar (yield) en el objeto WWW a medida que descarga el AssetBundle. Al utilizar esto, la función va simplemente parar en ese punto hasta que el objeto WWW haya terminado de descargar, pero no va a bloquear la ejecución del resto del código, este espera (yields) hasta que haya terminado. Hasta una sola descarga de AssetBundle puede finalizar por frame cuando son descargados con WWW.LoadFromCacheOrDownload.
  • Una vez el objeto WWW ha descargado el archivo AssetBundle, la propiedad .assetBundle es utilizada para obtener un objeto AssetBundle. Este objeto es la interfaz para cargar objetos del archivo AssetBundle.
  • En este ejemplo una referencia a un prefab en el AssetBundle es obtenida del AssetBundle utilizando la propiedad .mainAsset (asset principal). Esta propiedad es configurada cuando se construye el AssetBundle pasando un objeto como el primer parámetro. El asset principal en el AssetBundle puede ser utilizado para almacenar un TextAsset con una lista de objetos dentro del AssetBundle y cualquier otra información acerca de ellos.

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.

¿Cómo uso AssetBundles en el editor?

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.

Cómo puedo almacenar en caché los AssetBundles?

Usted puede utilizar WWW.LoadFromCacheOrDownload el cual automáticamente se ocupa de guardas sus AssetBundles en disco. Por favor tenga en cuenta que en el Webplayer usted está limitado a 50MB en total (compartido entre todos los webplayers). Usted puede comprar una licencia para almacenar en caché por separado para su juego si usted 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 multi-plataforma?

Los AssetBundles son compatibles entre algunas plataformas. Utilice la siguiente tabla como una guía.

Compatibilidad de plataforma para AssetBundles
Standalone Webplayer (Reproductor Web) iOS Android
Editor Y Y Y* Y*
Standalone Y Y
Webplayer (Reproductor Web) Y Y
iOS Y
Android Y

Por ejemplo, un bundle creado mientras el que el objetivo de construcción Webplayer estaba activo sería compatible con el editor y con las construcciones strandalone. Sin embargo, no sería compatible con apps construidas para las plataformas iOS o Android.

(*) Los AssetBundles construidos para plataformas móviles podrían contener datos almacenados en un formato de plataforma específico y optimizado que es incompatible con la plataforma en dónde el editor está corriendo. Tenga en cuenta que es seguro asumir que los juegos publicados necesitan diferentes asset bundles por plataforma. Específicamente los shaders son diferentes entre plataformas.

E.G los datos de GI son almacenados en un formato optimizado por la arquitectura ARM y por lo tanto no se pueden cargar en CPUs x86. Los shaders son almacenados para una configuración OpenGLES 2 y no se pueden cargar por el Editor que utiliza el renderizador DX9/11 (pero funciona con el renderizador OpenGLCore). Durante el desarrollo, a usted se le recomienda utilizar el Simulation Mode (modo de simulación) mencionado en el tutorial AssetBundles y el AssetBundle Manager para evitar la incompatibilidad del Editor y plataformas móviles.

Cómo son los assets en AssetBundles identificados?

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.

Puedo yo re-utilizar mis AssetBundles en otro juego?

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.

Un AssetBundle construido ahora puede ser utilizable con versiones futuras de Unity?

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.

Cómo puedo listar los objetos en un AssetBundle?

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.

Cómo los AssetBundles pueden referenciar otros assets en otros AssetBundles

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.

Incluyendo scripts en AssetBundles
Reduciendo el Tamaño del Archivo de la Construcción