Addressable Asset System入門
エンジニアの小松(@vtuber_watch)です。Synamon Advent Calendar 2021の21日目です。
UnityのAddressable Asset Systemの入門記事になります。Addressablesの紹介記事は多くありますが情報が古かったり必要な説明が抜けていたりするので最新のバージョンにおける情報をまとめています。
この記事では基本的な使い方を紹介します。アセットバンドルをビルドしてローカルからロードするまでをやります。これだけでもAddressablesの恩恵を受けられます。記事が長くなりすぎたのでアセットバンドルをサーバに配置する使い方は別記事に分割します。
目次
この記事はUnity 2021.2.6f1、Addressables 1.19.14における説明になります。
Addressable Asset Systemとは
Addressablesを使うとUnityのアセットをアセットバンドルにまとめていい感じに読み込みできるようになります。
Addressablesによって得られるメリットはたくさんありますがここではメモリ使用量の削減とアセットバンドルの扱いの2点から紹介します。
メリット1. メモリ使用量の削減
Addressablesを使うとメモリ使用量を減らせます。この点については以下のUnity Blogの記事で紹介されています。
記事の中では3つのプレハブ(Sword, Boss Sword, Shiled)をランタイムに生成する例を使って説明されています。
public class SampleMonoBehaviour : MonoBehaviour { // Addressablesを使わない場合 [SerializeField] private GameObject prefab; // Addressablesを使う場合 [SerializeField] private AssetReferenceT<GameObject> prefabReference; }
Addressablesを使わない場合、MonoBehaviourのフィールドにプレハブをGameObjectとして持ち、必要なときにインスタンス化します。
この方法はメモリ効率が悪いです。プレハブを直接参照しているためこのMonoBehaviourが存在する限りプレハブ全体がメモリに載ってしまいます。
Addressablesを使う場合、MonoBehaviourのフィールドに持つのはGameObjectではなくAssetReferenceT
これによって必要なときだけプレハブがメモリに載るようになります。不要になったときにアンロードすることもできます。
メリット2. アセットバンドルを簡単に使える
Addressables以前は、アセットバンドルを実用するには自前で管理するためのシステムを用意する必要がありました。アセットバンドルの構成設定とビルド、ロードとアンロード、依存関係の解決などかなりの実装が必要です。
Addresssablesではこれらの機能がすでに用意されており、簡単にアセットバンドルを使い始められます。多くの機能が拡張できるように作られているので必要な部分だけカスタマイズして使えます。
パッケージのインポートと初期設定
Addressablesを使い始めるにはまずパッケージをインストールします。
1. メニューのWindow/Package ManagerからPackageManagerを開き、Addressablesを選んでInstallボタンを押します。
2. インストールが完了したらメニューのWindows/Asset Management/Addressables/Groupsを押します。
3. Create Addressables Settingsボタンを押します。
以上でAddressablesがインストールされ、必要な設定ファイルが生成されました。
Addressablesの設定ファイルはAssets/AddressableAssetsDataフォルダに配置されます。
その中のAddressableAssetSettingsが全体の設定になります。
それぞれの設定の説明はマニュアルを見てください。今はデフォルトのままで大丈夫です。
使ってみる
初期設定は出来たのでとりあえず使ってみます。
プレハブをアドレス可能(Addressable)にする
まずはサンプルとして使うプレハブを作ります。何でもいいですがここではデフォルトのCubeだけのプレハブを作ります。
作成したプレハブを選択すると、インスペクタの一番上に「Addressable」というチェックボックスがあります。ここにチェックを入れるとそのアセットはアドレス可能(Addressable)になります。アドレス可能なアセットがAddressablesシステムでロードできます。
チェックボックス隣のテキストはこのアセットのアドレスです。デフォルトではアセットのパスになっていますが自由に変更できます。このアドレスを指定してアセットをロードします。
プレハブをインスタンス化する
作成したプレハブをロードしてみます。
ロードする方法はいくつかありますがここでは3つ紹介します。
- Addressables.LoadAssetAsyncはアドレスを指定してアセットをロードできます
- Addressables.InstantiateAsyncはアドレスを指定してプレハブをインスタンス化できます。
- AssetReferenceTはインスペクタでアセットを設定してアセットのロードやインスタンス化ができます。
1. Addressables.LoadAssetAsyncを使う
以下のスクリプトをシーンに配置して実行してください。プレハブがロードされてインスタンス化されます。
using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; public class SpawnerByLoadAssetAsync : MonoBehaviour { private AsyncOperationHandle<GameObject> prefabHandle; private GameObject spawnedGameObject; private async void Start() { // Addressables.LoadAssetAsyncで読み込む prefabHandle = Addressables.LoadAssetAsync<GameObject>("Assets/Prefabs/Cube.prefab"); // .Taskで読み込み完了までawaitできる GameObject prefab = await prefabHandle.Task; // 読み込んだプレハブをインスタンス化する spawnedGameObject = Instantiate(prefab); spawnedGameObject.name = "Spawned Game Object"; } private void OnDestroy() { // インスタンス化したGameObjectを破棄する Destroy(spawnedGameObject); // 使い終わったらhandleをリリースする Addressables.Release(prefabHandle); } }
アドレス可能なアセットはAddressables.LoadAssetAsyncでロードします。ここにロードしたいアセットのアドレスを指定します。
LoadAssetAsyncの戻り値はAsyncOperationHandle
また、Addressablesでロードしたアセットは使い終わったら必ずリリースする必要があります。Addressables.Releaseを使います。これを忘れるとプレハブが読み込まれたままになってしまうので注意してください。リリース漏れは後で紹介するEvent Viewerで確認できます。
内部では参照カウンタ方式でそのアセットが何ヵ所から使われているかをカウントしています。リリースするたびにカウントが減り、0になったらアセットがアンロードされます。
2. Addressables.InstantiateAsyncを使う
次のスクリプトも先のSpawnerByLoadAssetAsyncと同じような動作をします。
using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; public class SpawnerByInstantiateAsync : MonoBehaviour { private GameObject spawnedGameObject; private async void Start() { // Addressables.InstantiateAsyncでプレハブをインスタンス化する AsyncOperationHandle<GameObject> handle = Addressables.InstantiateAsync("Assets/Prefabs/Cube.prefab"); // .Taskでインスタンス化完了までawaitできる spawnedGameObject = await handle.Task; spawnedGameObject.name = "Spawned Game Object"; } private void OnDestroy() { // 使い終わったらインスタンスをリリースする Addressables.ReleaseInstance(spawnedGameObject); } }
Addressables.LoadAssetAsyncの代わりにAddressables.InstantiateAsyncを使っています。名前の通り、ロードする代わりに直接インスタンス化できます。
リリースでもAddressables.ReleaseではなくAddressables.ReleaseInstanceを使います。AsyncOperationHandleではなくインスタンス化されたGameObjectを渡してリリースできます。
Addressables.LoadAssetAsyncはGameObject以外のアセットもロードできますがAddressables.InstantiateAsyncはプレハブ専用です。プレハブをインスタンス化したい場合はAddressables.InstantiateAsyncの方が簡単に書けます。
3. AssetReferenceTを使う
先ほどの2つの方法はアドレスを指定してロードする方法でしたが、AssetReferenceTを使うとインスペクタでアセットを設定してロードできます。*1
次のコードをシーンに配置して、prefabReferenceにCubeプレハブを設定します。
using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; public class SpawnerByAssetReferenceT : MonoBehaviour { [SerializeField] private AssetReferenceT<GameObject> prefabReference; private GameObject spawnedGameObject; private async void Start() { // InstantiateAsyncでプレハブをインスタンス化する AsyncOperationHandle<GameObject> handle = prefabReference.InstantiateAsync(); // .Taskでインスタンス化完了までawaitできる spawnedGameObject = await handle.Task; spawnedGameObject.name = "Spawned Game Object"; } private void OnDestroy() { // 使い終わったらインスタンスをリリースする prefabReference.ReleaseInstance(spawnedGameObject); } }
ここではInstantiateAsyncを使ってプレハブをインスタンス化していますが、LoadAsyncもあるのでアセットのロードにも使えます。
AssetReferenceTはインスペクタで参照を設定できるのが強みです。特に理由がなければAssetReferenceTを使うのをお勧めします。
Addressables Groups
全てのアドレス可能なアセットはグループにわけて管理されます。
メニューのWindows/Asset Management/Addressables/Groupsでグループを管理できます。
画像のPrefabsやMaterialsがグループで、その下のAssets/Prefabs/Cube.prefabなどがグループに入っているアセットです。
グループは右クリックで新しく作成できます。グループにアセットをドラッグ&ドロップしてアセットを振り分けられます。
同じグループのアセットは1つのアセットバンドルとしてビルドされます。*2つまり、グループ単位でロードやアンロードが行われるということです。同じタイミングで使われるアセットを同じグループにしておくと効率が良くなります。
Play Mode Script
Play Mode Scriptメニューでエディタ上で実行したときの動作を設定できます。
「Use Asset Database」ではアセットバンドルを使わずにアセットを直接読み込みます。動作が速いので開発中にはこれを使います。
「Simulate Groups」ではアセットバンドルは使われませんが、グループの設定に従ってアセットバンドルの動きをシミュレートします。これによってEventViewerでアセットバンドルのロードやアンロードを監視できるようになります。
エディタ上でグループの設定を試すのに使えます。
「Use Existing Build」では実際にビルドされたアセットバンドルが使われます。あらかじめアセットバンドルをビルドしておく必要があります。
アセットバンドルのビルド
Build/New Build/Default Build Scriptでグループをアセットバンドルにビルドできます。ビルドはLibrary/com.unity.addressables/aaフォルダに出力されます。
ビルドされたアセットバンドルは、プロジェクトのビルド時には自動的にStreamingAssetsにコピーされます。これによって実機でも正しくアセットバンドルをロードできます。
グループの設定
Addressables Groupsでグループを選択するとグループごとの設定ができます。
ここではBuild & Load Pathsについて説明します。他の項目についてはマニュアルを見てください。
Build & Load Paths
一番上の「Build & Load Paths」でアセットバンドルをどこにビルドしてどこからロードするかを設定できます。
「Local」ではLibraryフォルダ内にビルドされ、プロジェクトのビルド時には自動的にStreamingAssetsにコピーされます。
ロードもEditor実行時はLibraryフォルダ、ビルドではStreamingAssetsから自動的に行われます。
「Remote」ではServerDataフォルダ内にビルドされます。ビルドしたアセットバンドルは手動でサーバなどにアップロードする必要があります。
ロード時にサーバからダウンロードされます。
「custom」ではパスを自由に設定できます。
Remoteに設定したときの詳しい使い方はまた別の記事で説明します。
Addressables Analyze
アセットバンドルには、そのグループに振り分けたアセットだけでなく、それらのアセットが依存するアセットも含めてビルドされます。
依存先のアセットがどこかのグループに入っていればそこへの参照が張られます。どこのグループにも入っていない場合は同じアセットバンドルに直接含まれます。実際にどのアセットがどのアセットバンドルに含まれるかをAddressables Analyzeで確認できます。
Addressables AnalyzeはAddressable GroupsのTools/Window/Analyzeメニューで表示できます。
「Analyze Select Rules」を押すとグループ設定を検証できます。
使ってみる
実際に以下のグループ設定で検証してみます。Cube.prefabとCube2.prefabはどちらもGreen.matというマテリアルに依存しています。
この状態で「Analyze Select Rules」を押すと以下のような結果になります。
アセットバンドルに含まれるアセット一覧はBundle Layout Previewに表示されています。
ここでは2つのアセットバンドルにGreen.matが暗黙的(Implicit)に含まれてしまっています。同じアセットが別々のアセットバンドルに含まれると、同じアセットが2重にロードされて効率が悪くなります。Analyze結果でも黄色い三角で警告として表示されています。
これを解決するにはGreen.matをどこかのグループに入れてしまえばOKです。「Fix Selected Rules」を押すと自動的に重複するアセットを新しいグループに隔離してくれます。実行するとGreen.matがDuplicate Asset Isolationというグループに入りました。
Addressables Event Viewer
Event Viewerを使うとアセットバンドルのロードやアンロードを監視できます。アセットのリリース漏れなどがないかを確認できます。
Event Viewerを使うには設定を変更する必要があります。
- AddressableAssetsData/AddressableAssetSettingsを選び、Send Profiler Eventsにチェックを入れます。
- Addressables GroupsでPlay Mode ScriptをSimulate GroupsまたはUse Existing Buildにします。
EventViewerはAddressable GroupsのTools/Window/Event Viewerで表示できます。エディタ上で実行開始すると以下のように現在の状態を見られます。
ここではCube.prefabが1つロードされていることがわかります。
まとめ
- グループに割り振られたアセットがアドレス可能となり、Addressablesシステムでロードできます。
- グループに割り振られたアセットがアセットバンドルとしてひとまとめにビルドされます。
- Addressables Analyzeを使ってアセットの重複を検査・修正できます。
- Addressables Event Veiwerを使ってアセットのリリース漏れを検査できます。