あるAssetBundleが別のAssetBundleに依存している場合、依存しているものを先に読み込まないとバグります。
AssetBundleの基本的な使い方になりますが、改めてこの挙動を確認してみます。
Unity2018.3.1
前提
前提として、この記事では以下のようにPrefabとそのPrefabが参照するMaterialをAssetBundleにすることを考えます。
またAssetBundleのビルドやロードの手順は割愛します。
ビルドについてはAssetBundle Browserを使用しているので必要に応じて次の記事を参考にしてください。
まず依存関係のないAssetBundleを読み込んでみる
まずPrefabとMaterialを一つのAssetBundleにまとめてみます。
この場合AssetBundleは一つしかないので、もちろんAssetBundle間の依存関係はありません。
この状態でAssetBundleをビルドすると、PrefabとMaterialの入ったAssetBundleが生成されます。
生成されたAssetBundleを下記のスクリプトで読み込んでみます。
var assetBundle = AssetBundle.LoadFromFile(assetBundlePath); var prefab = assetBundle.LoadAsset<GameObject>("Assets/AssetBundle/Prefab.prefab"); Instantiate(prefab); assetBundle.Unload(false);
結果は次の通り、正常にAssetBundleが読み込まれました。
依存先をロードしてからロードを行わないとバグる
次にPrefabとMaterialに別々のAssetBundle名を付けてビルドしてみます。
この状態でビルドすると二つのAssetBundleが作られます。
そしてPrefabはMaterialに依存しています。
ビルドしたフォルダ直下にある、フォルダ名と同じ名前の.manifestファイルを開くと、
AssetBundleの一覧とそれらの依存関係がわかります。
(ちなみにこの.manifestはランタイムでは使いません。)
ManifestFileVersion: 0 CRC: 1488167663 AssetBundleManifest: AssetBundleInfos: Info_0: Name: example/material Dependencies: {} Info_1: Name: example/prefab Dependencies: Dependency_0: example/material
この状態で、前節のスクリプトを使ってPrefabのAssetBundleを読み込んでみます。
Prefabは読みこめたもののMaterialへの依存関係が解決されていないため、ピンクになってしまいました。
依存関係を解決してロードする
あるAssetBundleの中のAssetをロードするときには、そのAssetが依存しているAssetBundleを先に全て読み込む必要があります。
つまり今回の例では、まずMaterialのAssetBundleを読み込んで、そのあとにPrefabのAssetBundleからPrefabを読み込む必要があります。
また、AssetBundleの依存関係は、ビルドしたフォルダの直下にある、
フォルダと同名のAssetBundle(.manifestファイルではなくAssetBundleの方)をロードすることで取得できます。
// ルートにあるAssetBundleからAssetBundleManifestを読み込む var rootBundle = AssetBundle.LoadFromFile(rootBundlePath); var manifest = rootBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); rootBundle.Unload(false); // 読み込み対象のAssetBundleが依存しているAssetBundleの一覧を取得してロード var dependencies = manifest.GetAllDependencies("example/prefab"); var dependencyBundles = new List<AssetBundle>(); foreach(var dependency in dependencies) { dependencyBundles.Add(AssetBundle.LoadFromFile(Path.Combine(assetBundleFolderPath, dependency))); } // 読み込み対象のAssetBundleをロード > インスタンス化 > アンロード var assetBundle = AssetBundle.LoadFromFile(assetBundlePath); var prefab = assetBundle.LoadAsset<GameObject>("Assets/AssetBundle/Prefab.prefab"); Instantiate(prefab); assetBundle.Unload(false); // 依存関係にあるAssetBundleをアンロード foreach (var dependencyBundle in dependencyBundles) { dependencyBundle.Unload(false); }
補足として、上記ではPrefabのAssetBundleを最後に読み込んでいますが、
依存関係が評価されるのはあくまでAssetBundle.LoadAsset()
の時点です。
そのため、PrefabのAssetBundleのロードは必ずしも最後にやらなくてもOKです。
これを実行すると、
AssetBundle同士の依存関係が解決されて正常にロードが完了しました。
まとめ
- AssetBundle同士の依存関係がある場合には依存しているAssetBundleを先にロードしておく必要がある
- 依存関係の情報はルートにあるAssetBundleに書かれている
ということがわかりました。