Unity により、アプリケーションにおいて、特定のアセットバンドルには一度にひとつのインスタンスのみ持つことができます。つまり、もし同じものが以前にロードされていてアンロードされていなければ、WWW オブジェクトからアセットバンドルを取得できないということです。実際的には以前にロードされたアセットバンドルをアクセスするときは次のようにします:
AssetBundle bundle = www.assetBundle;
Cannot load cached AssetBundle. A file of the same name is already loaded from another AssetBundle
Unity 5 以前は、バンドルをアンロードする前に、すべてのバンドルがロード完了していなければならないことに注意してください。いくつかのバンドルがまだロードされている間、AssetBundle.Unload 関数を呼び出してもすべてのバンドルがロードされるまでコードの残りの部分の実行をブロックします。これはパフォーマンスの遅延やしゃっくり状態(hiccup)を発生させます。また、これは Unity 5 で改善しました。
もしどのアセットバンドルがダウンロードされたかトラッキングする場合は、ラッパークラスを使ってダウンロードを次のように管理します:
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
static public class AssetBundleManager {
// A dictionary to hold the AssetBundle references
static private Dictionary<string, AssetBundleRef> dictAssetBundleRefs;
static AssetBundleManager (){
dictAssetBundleRefs = new Dictionary<string, AssetBundleRef>();
}
// Class with the AssetBundle reference, url and version
private class AssetBundleRef {
public AssetBundle assetBundle = null;
public int version;
public string url;
public AssetBundleRef(string strUrlIn, int intVersionIn) {
url = strUrlIn;
version = intVersionIn;
}
};
// Get an AssetBundle
public static AssetBundle getAssetBundle (string url, int version){
string keyName = url + version.ToString();
AssetBundleRef abRef;
if (dictAssetBundleRefs.TryGetValue(keyName, out abRef))
return abRef.assetBundle;
else
return null;
}
// Download an AssetBundle
public static IEnumerator downloadAssetBundle (string url, int version){
string keyName = url + version.ToString();
if (dictAssetBundleRefs.ContainsKey(keyName))
yield return null;
else {
while (!Caching.ready)
yield return null;
using(WWW www = WWW.LoadFromCacheOrDownload (url, version)){
yield return www;
if (www.error != null)
throw new Exception("WWW download:" + www.error);
AssetBundleRef abRef = new AssetBundleRef (url, version);
abRef.assetBundle = www.assetBundle;
dictAssetBundleRefs.Add (keyName, abRef);
}
}
}
// Unload an AssetBundle
public static void Unload (string url, int version, bool allObjects){
string keyName = url + version.ToString();
AssetBundleRef abRef;
if (dictAssetBundleRefs.TryGetValue(keyName, out abRef)){
abRef.assetBundle.Unload (allObjects);
abRef.assetBundle = null;
dictAssetBundleRefs.Remove(keyName);
}
}
}
このクラスの使用例は:
using UnityEditor;
class ManagedAssetBundleExample : MonoBehaviour {
public string url;
public int version;
AssetBundle bundle;
void OnGUI (){
if (GUILayout.Label ("Download bundle"){
bundle = AssetBundleManager.getAssetBundle (url, version);
if(!bundle)
StartCoroutine (DownloadAB());
}
}
IEnumerator DownloadAB (){
yield return StartCoroutine(AssetBundleManager.downloadAssetBundle (url, version));
bundle = AssetBundleManager.getAssetBundle (url, version);
}
void OnDisable (){
AssetBundleManager.Unload (url, version);
}
}
このサンプルで AssetBundleManager クラスが static であることに注意する必要があり、新しいシーンをロードするとき参照するすべてのアセットバンドルは破棄されません。このクラスをガイドとして使用するのはよいですが、最初に述べたように使用した直後にアセットバンドルを アンロード するのがベストです。先にインスタンス化されたオブジェクトをいつでも複製することが可能で、再度アセットバンドルをロードする必要がなくなります。
次のエラーが返されます そして assetBundle は null を返します。もし一回目がまだロードされている場合、二回目のダウンロードではアセットバンドルを取得できないため、やらなければいけないこととしては、アセットバンドルを使用しなくなったときに アンロード するか、または参照を維持して、すでにメモリにあるときはダウンロードすることを避けることです。ニーズによって、取るべきアクションは判断できますが、推奨はオブジェクトのロード完了したら直ちにアセットバンドルを アンロード することです。これによりメモリが解放され、キャッシュしたアセットバンドルをロードするときのエラーが出なくなります。