AssetBundle設計のとある形

前回、AssetBundleを利用する際に考慮すべきことを記事にしましたが、その実例を紹介したいと思います。全体的に何を考慮すべきなのかを知りたい人は、前の記事「AssetBundle設計コトハジメ」を見てください。

●1つのAssetBundleに含めるAssetの数やルール

基本的には1Asset = 1AssetBundle。
ただし、同時利用することが確定しているAssetは、複数まとめてAssetBundle化します。

また、

こんなイメージでAssetをロードする側が、非同期でAssetのロードを待ち、そのAssetがアプリ内(Resources/)からロードされるのか、ダウンロードが必要なのかは基本的に意識しないつくりにしています。

そのため、Resources以下に配置するAssetのパスとAssetBundleのパスは同一にする、というルールにしています。

例:

hoge/hogehoge.png」の場合、以下のようになります。

Assetをロードする場合に指定するパス         :hoge/hogehoge
アプリ内に配置する場合のAssetのパス         :Resources/hoge/hogehoge.png
ダウンロードする場合のAssetBundleのパス:https/xxx/hoge/hogehoge.assetbundle

複数Assetを1つのAssetBundleにする場合は、ディレクトリ名をAssetBundle名にします。

例:

chara01/hoge.pngとchara01/fuga.png」を一つのAssetBundleに含める場合、以下のようになります。

Assetをロードする場合に指定するパス:chara01/hoge, chara01/fuga
アプリ内に配置する場合のAssetのパス :Resources/chara01/hoge.png, Resources/chara01/fuga.png
ダウンロードする場合のAssetBundleのパス:https/xxx/chara01.assetbundle

このように、パスやリソースのロードを工夫することで、アプリ内(Resources/)に配置するAssetとダウンロードするAsset(別ディレクトリ)を簡単に入れ替えられるようにしています。

また、この構成から察するかもしれませんが、ダウンロードするタイミングは、Assetが必要になった(ロード要求をした)タイミングになります。アプリ起動時など、特定のタイミングでダウンロードを済ませて起きたい場合は、予めダウンロードするAssetのリストを作っておき、そのタイミングでまとめてロードする、といった使い方も可能です。

 

●Unloadするタイミング

前述のとおり、今回はAssetBundleに含まれるAssetはすべて同時利用されるのと、Unity5.3から登場したLZ4形式なら必要な分だけしかメモリを消費しないため、Assetをロード後にすぐUnloadするのではなく、Assetへの参照がなくなった時点でUnloadするようにしています。

 

●ロード方法と圧縮形式

現状はキャッシュ(WWW.LoadFromCacheOrDownload、UnityWebRequest.GetAssetBundle)を利用しているため、
「LZMA(ダウンロード時) → LZ4(端末に保存、ロード時)」
となります。

今のところダウンロードするリソースの量はそれほど多くない予定ですが、バージョン管理の仕組みなどは用意したため、後でAssetBundle.LoadFromFileを使った実装に変える、というのも比較的容易にできるようにつくったつもりです。

 

●AssetBundleビルドの工夫

基本的には1Asset = 1AssetBundleのため、指定したディレクトリ以下にあるAssetはAssetBundle名を自動で設定しています。

ディレクトリ単位でAssetBundleにしたい場合は、エディタ拡張のメニューで設定を変更します。

※GroupFlg Onにするとディレクトリ名のAssetBundleに対象Assetが含まれるようになります
※特定のルールが決まったディレクトリはAssetImporterで自動設定しています

EditorWindowを利用して、AssetImporterのassetBundleName、assetBundleVariant、userDataあたりを設定しています。

参考:

https://docs.unity3d.com/ja/current/ScriptReference/EditorWindow.html
https://docs.unity3d.com/jp/current/ScriptReference/AssetImporter.html

AssetBundle名の命名規則とこの対応で、手入力によるAssetBundle名の設定は撲滅しています。

AssetBundleビルドからアプリにダウンロードされるまでのフローは以下のようになります。


①Assetbundleビルド(図左上)

専用マシンを用意して、AssetBundleの対象ファイルを追加したり変更する際は、そのマシンで行うようにしています。こうすることで、UnityのAssetBundleビルドが差分だけ走るようにしています。(git経由で別マシンからプッシュしたAssetは再度AssetBundleビルドが走ってしまったり、ファイルの更新日時も変わってしまって管理しづらいため)

ビルド時に、更新されたAssetBundleの更新日時を元に、AssetBundle毎のバージョンを上げていきます。


②アップロード(図左下)

AssetBundleビルド後に更新があったAssetBundleはワンクリックでサーバへアップできるようにしています。この際に、AssetBundleのバージョン情報をcsvファイルに吐き出して、git経由でAPIサーバが参照するDBに登録します。アプリからはこのバージョンを参照してダウンロード判定を行います。


③端末からのAPI通信時(図右下)

アプリからサーバに通信を行う際に、AssetBundle(リソース)のバージョンチェックを行います。新しいバージョンが登録されている場合、そのリストを取得します。


④リソース(Asset)ロード時(図右上)

Assetをロードする際に、③で取得したバージョンをチェックし、未ダウンロードの場合や新しいAssetBundleがサーバ上にある場合、ダウンロードした後にAssetをロードします。ダウンロード対象のAssetじゃない場合はアプリ内(Resources)からロードします。


 

●依存関係とAssetBundleManifest

AssetBundleビルド時にできるAssetBundleManifestから、独自の管理ファイルを作成しています。

用途としては、AssetBundleManifestと同じく依存関係の管理と、バージョン管理、AssetとAssetBundleの紐付けを確認するためのものです。

 

●まとめ

実現したもの

 ・アプリ内に配置するAssetとダウンロードするAssetの入れ替えを容易に

 ・AssetBundle名の自動設定

 ・AssetBundleビルドした後のリソースをワンクリックでサーバへアップロード

 ・AssetBundleの依存関係を動的に解決

 ・バージョン管理の仕組み

残っている課題

 ・不要になったAssetBundleを削除する仕組み

 ・同時ダウンロード数の制御
となります。