Version: 5.5
Optimizing disk seeks with AssetBundles
Reducing the file size of your build

Часто задаваемые вопросы об AssetBundles

Как мне использовать AssetBundle?

Два важных этапа задействованы при работе с AssetBundle’ами. На первом этапе происходит скачивание AssetBundle с сервера или диска. Это происходит с помощью класса WWW. На втором этапе загружаются ассеты из AssetBundle для использования их в приложении. Вот пример C# скрипта:

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());
    }
}

Этот скрипт добавлен на GameObject как Component. AssetBundle загружается следующим образом:

  • Переменные url и version необходимо установить в окне Inspector перед запуском этого скрипта. Переменная url указывает путь к файлу AssetBundle, обычно на сервере в Интернете. Переменная version позволяет разработчику ассоциировать число (версию) с AssetBundle во время записи в кэш на диск. Unity проверяет существование AssetBundle в кэше при его скачивании. Если он существует, то проверяется версия хранимого ассета с запрашиваемой версией. Если версии различаются, то AssetBundle перезагружается. Если они одинаковы, то AssetBundle загружается с диска и таким образом избегается перекачивание файла. За более детальной информацией про эти параметры обратитесь к функции WWW.LoadFromCacheOrDownload в справке по скриптингу.
  • When the Start function of this script is called, it will start loading the AssetBundle by calling the function as a Coroutine.The function will yield on the WWW object as it downloads the AssetBundle. By using this, the function will simply stop in that point until the WWW object is done downloading, but it will not block the execution of the rest of the code, it yields until it is done. Only up to one AssetBundle download can finish per frame when they are downloaded with WWW.LoadFromCacheOrDownload.
  • Как только объект WWW скачает AssetBundle файл, свойство .assetBundle используется для получения объекта AssetBundle. Этот объект является интерфейсом для загрузки объектов из AssetBundle файла.
  • В данном примере ссылка на префаб получается из AssetBundle через свойство .mainAsset. Это свойство устанавливается во время конструирования AssetBundle при передаче объекта в качестве первого параметра. Главный ассет из AssetBundle может быть использован для хранения TextAsset со списком объектов внутри AssetBundle и любой другой информацией о них.

Пожалуйста, отметьте, что для простоты предыдущего примера он не делает проверок на безопасность. Пожалуйста, для более полного примера взгляните сюда.

Как использовать AssetBundles в редакторе?

Поскольку создание приложения - это итеративный процесс, вы, скорее всего, будете модифицировать свои ассеты много раз. Это потребует пересоздания AssetBundles после каждого изменения, чтобы вы смогли их тестировать. Хотя и есть возможно загружать AssetBundle’ы в редакторе, это делать не рекомендуется. Вместо этого для тестирования вы должны использовать вспомогательную функцию Resources.LoadAssetAtPath, чтобы избежать необходимости использования и пересоздания AssetBundle’ов. Такая функция позволит вам загрузить ассет так, как будто он загружен из AssetBundle, но при этом пропуская этап построения AssetBundle, и кроме того, ваши ассеты всегда находятся в актуальном состоянии.

Далее приведен пример вспомогательного скрипта, позволяющего вам загружать ассеты в зависимости от того, запущен он в редакторе или нет. Добавьте этот код в С# скрипт с именем 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
    }
}

Теперь мы можем использовать скрипт AssetBundleLoader для загрузки ассетов из AssetBundle, если мы запускаем созданное приложение, или для загрузки ассета непосредственно из папки, если мы запускаем его из редактора:

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" : "");
    }
}

Предыдущий скрипт следует сохранить в файл с именем ExampleLoadingBundle.cs внутри папки Assets. После установки публичным переменным корректных значений и запуска скрипта, он, используя класс AssetBundleLoader, загрузит ассет. Далее ассет будет создан и отображен с использованием GUI.

Как кэшировать AssetBundle’ы?

Вы можете использовать функцию WWW.LoadFromCacheOrDownload, которая автоматически сохранит ваши AssetBundle’ы на диск. Будьте внимательны, так как Webplayer ограничен размером в 50МБ (общее для всех веб-проигрывателей). Вы можете приобрести отдельную лицензию для вашей игры, если вам необходимо больше пространства для кэша.

Если ваши AssetBundle’ы хранятся в папке StreamingAssets в виде распакованных AssetBundle’ов, вы можете использовать AssetBundle.CreateFromFile для обращения к AssetBundle’у на диске. Если AssetBundle’ы в папке StreamingAssets сжаты, вам придётся использовать WWW.LoadFromCacheOrDownload для создания распакованной копии AssetBundle в кэше.

Кросс-платформенные ли AssetBundle’ы?

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

Совместимость платформ для AssetBundle’ов
Автономная сборка iOS Android
Редактор Да Y* Y*
Автономная сборка Да
iOS Да
Android Да

(*) 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.

Как идентифицируются ассеты в AssetBundle’ах?

При создании AssetBundle’ов ассеты идентифицируются их именами без расширения. К примеру, текстура в папке проекта (“Assets/Textures/myTexture.jpg”) идентифицируется и загружается по имени “myTexture”, если вы используете метод по умолчанию. Вы можете повлиять на это в большей степени, если также передадите ваш собственный массив идентификаторов (строк) для каждого объекта при создании вашего AssetBundle в метод BuildPipeline.BuildAssetBundleExplicitAssetNames.

Возможно ли повторно использовать AssetBundle’ы в другой игре?

AssetBundles позволяют вам использовать контент в разных играх. Единственное требование - любой ассет, на который ссылаются GameObject’ы в вашем AssetBundle, должен быть включен в AssetBundle. Чтобы убедиться, что все ссылаемые ассеты включены в AssetBundle, передайте флаг BuildAssetBundleOptions.CollectDependencies во время его создания.

Будет ли созданный AssetBundle совместим с будущими версиями Unity?

AssetBundles can contain a structure called a type tree, which allows information about Asset types to be understood correctly between different versions of Unity. The type tree is included by default on almost all platforms, but can be disabled by passing the BuildAssetBundleOptions.DisableWriteTypeTree to the BuildAssetBundle function.

Type trees are not supported when using the .NET scripting backend with Windows Store/Universal Windows Platform targets, so you need to rebuild these bundles whenever the serialization format changes. This can happen in newer versions of Unity. It also happens if you add or remove serialized fields in MonoBehaviours that are included in the AssetBundle. When loading an AssetBundle, Unity gives you an error message if the AssetBundle must be rebuilt.

Как получить список объектов из AssetBundle?

You can use AssetBundle.LoadAllAssets 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.

How can AssetBundles reference assets in other AssetBundles

Suppose Bundle A contains a Prefab which has a material and texture. Bundle B has a scene which has an instance of the same prefab. Bundle B needs to access the material. Unless the material is included in a specific asset bundle it will be included in both bundle A and B.

Optimizing disk seeks with AssetBundles
Reducing the file size of your build