AssetBundle (アセットバンドル) のロードには、次の 2 種類の API を使用できます。
この API はファイルのコンテンツをディスクから直接、増分のみ読み取ることができるため、非圧縮およびチャンク圧縮バンドル (LZ4) をローカル ストレージからロードする場合に、非常に効率的です。このメソッドを使用して通常のファイル圧縮 (LZMA) で圧縮されたファイルをロードすると、最初にファイルをメモリ内に完全に解凍する必要があるため、効率が低下します。
以下は LoadFromFile の使用方法の一例です。
using System.IO;
using UnityEngine;
public class LoadFromFileExample : MonoBehaviour
{
void Start()
{
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
return;
}
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
Instantiate(prefab);
}
}
ロードプロセス中にアプリケーションをブロックする代わりに、非同期バージョンの AssetBundle.LoadFromFileAsync を使用することもできます。
アセットバンドルが実際にはローカルファイルに保存されていない場合にロードする方法は、他にもいくつかあります。例えば、AssetBundle.LoadFromMemoryAsync を使用できます。
UnityWebRequestAssetBundle API を呼び出して、アセットバンドルをダウンロード、キャッシュ、ロードするための特別なウェブリクエストを作成できます。
通常、URL はウェブサービスによって公開されたファイルを指し示す ‘https://’ のアドレスです。また、ファイルシステムへの直接アクセスをサポートしないプラットフォームでローカル データにアクセスする ‘file://’ もあります。
このリクエストを DownloadHandlerAssetBundle.GetContent(UnityWebRequestAssetBundle) に渡すことで、ロードされたアセットバンドル用の AssetBundle オブジェクトを取得できます。
以下に例を示します。
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class DownloadExample : MonoBehaviour
{
IEnumerator Start()
{
string uri = "https://myserver/myBundles/bundle123";
uint crc = 1098980; // Expected content CRC
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri, crc);
yield return request.SendWebRequest();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
var loadAsset = bundle.LoadAssetAsync<GameObject>("Assets/Players/MainPlayer.prefab");
yield return loadAsset;
Instantiate(loadAsset.asset);
}
}
または、2023.1 以降は await をサポートしています。
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class DownloadExample : MonoBehaviour
{
async void Start()
{
string uri = "https://myserver/myBundles/bundle123";
uint crc = 1098980; // Expected content CRC
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri, crc);
await request.SendWebRequest();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
var loadAsset = bundle.LoadAssetAsync<GameObject>("Assets/Players/MainPlayer.prefab");
await loadAsset;
Instantiate(loadAsset.asset);
}
}
説明を簡単にするために、この例ではコードにハードコードされた CRC 値を示しています。ただし実際には、アセットバンドルに期待される CRC 値は、アセットバンドルをダウンロードする前に個別にダウンロードされるか、ファイルから取得されます。アセットバンドルのダウンロードの整合性とセキュリティを参照してください。
注意このコードが呼び出されるたびにアセットバンドルのコンテンツ全体がダウンロードされるのを防ぐために、アセットバンドルのキャッシュを有効にすることができます。これは、UnityWebRequestAssetBundle.GetAssetBundle を呼び出すときにアセットバンドルハッシュを渡すことで実施されます。ハッシュは、このセクションで後述するアセットバンドルマニフェストから使用できます。ハッシュは、要求しているアセットバンドルの正確なビルドのバージョン識別子として機能します。キャッシュの詳細と圧縮に関する考慮事項については、アセットバンドルの圧縮とキャッシュを参照してください。
アセットバンドルのダウンロードに成功したら、アセットのロードを開始できます。
汎用コード スニペット
T objectFromBundle = bundleObject.LoadAsset<T>(assetName);
T は、読み込むアセットのタイプです。
アセットのロード方法はいくつかあり、LoadAsset、LoadAllAssets、およびそれらの非同期カウンターパートである LoadAssetAsync、LoadAllAssetsAsync が挙げられます。
アセットバンドルから同期的にアセットを読み込む方法は以下の通りです。
アセット 1 つ (例えばプレハブのルートゲームオブジェクト) をロードするには、以下を行います。
GameObject gameObject = loadedAssetBundle.LoadAsset<GameObject>(assetName);
全てのアセットを読み込むには以下を使用します。
Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();
これは各アセットのすべてのルートオブジェクトを含む配列を返します。
上述のメソッドは、ロード中のオブジェクトのタイプ、またはオブジェクトの配列を返しますが、非同期メソッドでは AssetBundleRequest を返します。アセットにアクセスする前に、この処理が完了している必要があります。非同期でアセットをロードするには以下を行います。
AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync<GameObject>(assetName);
yield return request; // or await request;
var loadedAsset = request.asset;
または
AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
yield return request; // or await request;
var loadedAssets = request.allAssets;
アセットをロードしたら準備完了です。ロードされたオブジェクトは、Unity の他のオブジェクトと同様に使用できます。
アセットバンドルマニフェストのロードは非常に役立ち得ます。特にアセットバンドルの依存関係を扱う場合には有益です。
使用可能な AssetBundleManifest オブジェクトを取得するには、追加のアセットバンドル (格納されているフォルダーと同じ名前のアセットバンドル) をロードし、AssetBundleManifest タイプのオブジェクトを 1 つ、そこからロードする必要があります。
マニフェスト自体の読み込みは、その他通常のアセットをアセットバンドルから読み込む場合と全く同じように行われます。
AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
これで、上記の例にあるマニフェストオブジェクトによって AssetBundleManifest API 呼び出しが使用できるようになりました。ここからは、ビルドしたアセットバンドルの情報を、マニフェストを使用して取得することができます。この情報には、該当のアセットバンドルの依存関係データ、ハッシュデータ、バリアントデータが含まれます。
アセットバンドルの依存関係に関する前のセクションでは、アセットバンドルからアセットをロードするために、最初にそのアセットバンドルが依存するアセットバンドルをロードする方法について説明しました。マニフェストオブジェクトを使用すると、依存関係を動的に検索してロードできるため、すべてのアセットバンドル名とそれらの関係をコード内で明示的にハードコードする必要はありません。例えば、“assetBundle” という名前のアセットバンドルのすべての依存関係をロードするとします。
AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] dependencies = manifest.GetAllDependencies("assetBundle"); //Pass the name of the bundle you want the dependencies for.
foreach(string dependency in dependencies)
{
AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
}
これでアセットバンドル、アセットバンドルの依存関係、アセットの読み込みが完了しました。次は、読み込んだアセットバンドルの管理についての解説です。
##ロードしたアセットバンドルの管理
注意Addressables パッケージは、アセットバンドル、依存関係、アセットのロードを管理するために、そのまま使用できるシステムを提供します。Unity では、アセットバンドルを自分で管理するよりも Addressable を使うことを推奨しています。
関連項目ロードしたアセットバンドルの管理に関する Unity Learn チュートリアル
Unity では、アクティブなシーンから削除されたオブジェクトは自動的にアンロードされません。アセットのクリーンアップは特定の時点でトリガーされますが、手動でトリガーすることも可能です。
アセットバンドルのロードとアンロードのタイミングを把握することが重要です。アセットバンドルのアンロードが不適切な場合、メモリ内でオブジェクトの重複や欠落が生じる可能性があります。
アセットバンドルの管理について理解すべき最大のポイントは、AssetBundle.Unload(bool) – または AssetBundle.UnloadAsync(bool) – をいつ呼び出すか、そして関数呼び出しに true または false を渡すべきかという点です。アンロードは、アセットバンドルヘッダーやその他のデータ構造をメモリから削除し、アセットバンドルをアンロードする非静的機能です。引数は、そのアセットバンドルからインスタンス化された全てのオブジェクトもアンロードするかどうかを示します。
AssetBundle.Unload(true) は、アセットバンドルからロードされたすべてのゲームオブジェクト (とその依存関係) をアンロードします。シーンにコピーしたオブジェクト (Instantiate の呼び出しなど) はアンロードされません。コピーされたデータはアセットバンドルに属していないためです。シーン内のオブジェクトが、アセットバンドルからロードされた (かつ、まだアセットバンドルに属している) テクスチャを参照している場合、この呼び出しによってテクスチャが非表示になり、Unity では欠落したテクスチャとして扱われます。
例として、下の図のようにアセットバンドル AB からマテリアル M がロードされ、プレハブ P で使用されるとします。
AB.Unload(true) が呼び出されると、アクティブなシーン内でオブジェクトが参照する M のインスタンスは破棄されます。
代わりに AB.Unload(false) を呼び出すと、M のインスタンスはメモリに残り、元のアセットバンドルにリンクされていない独立したオブジェクトになります。
後から AB が再度ロードされても、M の既存のコピーがアセットバンドル内のマテリアルに再リンクされることはありません。
プレハブ P の別のインスタンスを作成すると、既存の M のコピーは使用されず、代わりに M の 2 つ目のコピーがロードされます。
一般に、AssetBundle.Unload(false) を使用すると、オブジェクトの重複やその他の問題が発生する可能性があるため、ほとんどのプロジェクトでは、AssetBundle.Unload(true) を使用してこれを避ける必要があります。AssetBundle.Unload(true) を安全に呼び出すための一般的な方法は 2 つあります。
アプリケーションのライフタイム内で、一時的なアセットバンドルをアンロードする丁度良いタイミングを設定する。例えばステージとステージの間やロード画面など。
個々のオブジェクトの参照カウントを維持し、アセットバンドルに含まれるオブジェクトがすべて未使用である場合にのみ、アセットバンドルをアンロードする。この方法により、メモリで重複を生じることなく、アプリケーションによって個々のオブジェクトをアンロードおよびリロードできます。
どうしても AssetBundle.Unload(false) を使用する必要があるアプリケーションの場合に個々のオブジェクトをアンロードする方法は、以下の 2 つのみです。
不要なオブジェクトへのリファレンスをすべて削除します。例えば、他のロードされたオブジェクトから、不要なオブジェクトを指すフィールドをなくします。その後、Resources.UnloadUnusedAssets を呼び出します。
非加算的にシーンをロードします。これにより、現在のシーン内のすべてのオブジェクトが破棄され、Resources.UnloadUnusedAssets が自動的に実行されます。