Два важных этапа задействованы при работе с 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 загружается следующим образом:
Пожалуйста, отметьте, что для простоты предыдущего примера он не делает проверок на безопасность. Пожалуйста, для более полного примера взгляните сюда.
Поскольку создание приложения - это итеративный процесс, вы, скорее всего, будете модифицировать свои ассеты много раз. Это потребует пересоздания 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.
Вы можете использовать функцию WWW.LoadFromCacheOrDownload, которая автоматически сохранит ваши AssetBundle’ы на диск. Будьте внимательны, так как Webplayer ограничен размером в 50МБ (общее для всех веб-проигрывателей). Вы можете приобрести отдельную лицензию для вашей игры, если вам необходимо больше пространства для кэша.
Если ваши AssetBundle’ы хранятся в папке StreamingAssets в виде распакованных AssetBundle’ов, вы можете использовать AssetBundle.CreateFromFile для обращения к AssetBundle’у на диске. Если AssetBundle’ы в папке StreamingAssets сжаты, вам придётся использовать WWW.LoadFromCacheOrDownload для создания распакованной копии 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’ов ассеты идентифицируются их именами без расширения. К примеру, текстура в папке проекта (“Assets/Textures/myTexture.jpg”) идентифицируется и загружается по имени “myTexture”, если вы используете метод по умолчанию. Вы можете повлиять на это в большей степени, если также передадите ваш собственный массив идентификаторов (строк) для каждого объекта при создании вашего AssetBundle в метод BuildPipeline.BuildAssetBundleExplicitAssetNames.
AssetBundles позволяют вам использовать контент в разных играх. Единственное требование - любой ассет, на который ссылаются GameObject’ы в вашем AssetBundle, должен быть включен в AssetBundle. Чтобы убедиться, что все ссылаемые ассеты включены в AssetBundle, передайте флаг BuildAssetBundleOptions.CollectDependencies во время его создания.
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.
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.
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.