概要
動作確認環境: Unity 2022.3 LTS / Unity 6
「ビルドサイズが大きすぎる…」「メモリ管理が複雑で大変…」「ダウンロードコンテンツを配信したい…」
Unity開発をしていると、アセット管理の問題に直面することがあります。Addressables(アドレサブル) は、Unity公式のアセット管理システムです。AssetBundleをベースにしながら、依存関係の管理、メモリ管理、ロード元の切り替えを自動化します。これにより、複雑なアセット管理をシンプルに実現できます。
AssetBundleとの違い
AssetBundle は、アセットを圧縮してビルドサイズを削減したり、ダウンロードコンテンツを配信したりするための低レベルな仕組みです。しかし、AssetBundleを実際に使うには、依存関係の管理、メモリ管理、ロード元の切り替えな ど、多くの実装が必要でした。
Addressablesは、内部的にはAssetBundleを使用していますが、これらの複雑な管理を自動化します。開発者は、アセットに「アドレス」を付けて、そのアドレスでロードするだけです。
インストール方法
Addressablesは、Package Managerからインストールできます。
- Unityエディタのメニューから「Window」→「Package Manager」を選択
- 左上のドロップダウンメニューから「Unity Registry」を選択
- リストから「Addressables」を探してクリック
- 右下の「Install」ボタンをクリック
インストールが完了すると、アセットのインスペクターに「Addressable」チェックボックスが表示されるようになります。
アセットをAddressable化する
方法1:インスペクターでAddressableにする
最も簡単な方法は、アセットのインスペクターで「Addressable」チェックボックスをオンにすることです。
- Projectウィンドウでアセットを選択
- インスペクターで「Addressable」チェックボックスをオン
- アドレス名を設定(デフォルトはアセットのパス)
方法2:AssetReferenceフィールドに割り当てる
MonoBehaviourやScriptableObjectにAssetReferenceフィールドを追加し、インスペクターでアセットを割り当てることでも、Addressable化できます。
using UnityEngine;
using UnityEngine.AddressableAssets;
public class Example : MonoBehaviour
{
public AssetReference assetReference;
}
アセットのロード方法
方法1:アドレス文字列でロード(Completedコールバック)
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class LoadByAddress : MonoBehaviour
{
void Start()
{
Addressables.LoadAssetAsync<GameObject>("Enemy").Completed += OnLoadCompleted;
}
void OnLoadCompleted(AsyncOperationHandle<GameObject> handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
GameObject prefab = handle.Result;
Instantiate(prefab);
}
else
{
Debug.LogError($"Failed to load asset: {handle.OperationException}");
}
}
}
方法1.5:async/awaitでロード(推奨)
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class LoadByAddressAsync : MonoBehaviour
{
private AsyncOperationHandle<GameObject> handle;
async void Start()
{
try
{
handle = Addressables.LoadAssetAsync<GameObject>("Enemy");
GameObject prefab = await handle.Task;
Instantiate(prefab);
}
catch (System.Exception e)
{
Debug.LogError($"Failed to load asset: {e.Message}");
}
}
void OnDestroy()
{
if (handle.IsValid())
Addressables.Release(handle);
}
}
async/awaitのメリット: コールバック地獄を避けられ、try-catchでエラーハンドリングが直感的に書けます。
注意:
async voidはfire-and-forget(発火して忘れる)パターンとなり、例外が呼び出し元に伝播しません。本格的なプロジェクトではUniTask や Unity 6のAwaitable の使用を検討してください。
方法2:AssetReferenceでロード
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class LoadByReference : MonoBehaviour
{
public AssetReference assetReference;
void Start()
{
assetReference.LoadAssetAsync<GameObject>().Completed += OnLoadCompleted;
}
void OnLoadCompleted(AsyncOperationHandle<GameObject> handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
GameObject prefab = handle.Result;
Instantiate(prefab);
}
}
void OnDestroy()
{
assetReference.ReleaseAsset();
}
}
方法2.5:InstantiateAsyncでロードと生成を同時に
InstantiateAsyncを使うと、ロードとインスタンス化を1ステップで行えます。
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class InstantiateExample : MonoBehaviour
{
public AssetReference assetReference;
private AsyncOperationHandle<GameObject> handle;
private GameObject spawnedObject;
void Start()
{
handle = assetReference.InstantiateAsync(transform.position, Quaternion.identity);
handle.Completed += OnInstantiateCompleted;
}
void OnInstantiateCompleted(AsyncOperationHandle<GameObject> op)
{
if (op.Status == AsyncOperationStatus.Succeeded)
{
spawnedObject = op.Result;
Debug.Log($"Instantiated: {spawnedObject.name}");
}
}
void OnDestroy()
{
// InstantiateAsyncで生成したオブジェクトはReleaseInstanceでアンロード
// これにより生成されたGameObjectも破棄される
if (handle.IsValid())
Addressables.ReleaseInstance(handle);
}
}
ライフサイクルの注意:
ReleaseInstanceを呼ぶと、生成されたGameObjectも自動的に破棄されます。オブジェクトを手動でDestroyした場合でも、ReleaseInstanceでハンドルを解放してください。
方法3:ラベルでロード
複数のアセットに同じラベルを付けて、そのラベルで一度にロードすることもできます。
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using System.Collections.Generic;
public class LoadByLabel : MonoBehaviour
{
private List<GameObject> loadedPrefabs = new List<GameObject>();
private AsyncOperationHandle<IList<GameObject>> handle;
void Start()
{
handle = Addressables.LoadAssetsAsync<GameObject>(
"enemies",
prefab => {
// 各アセットがロードされるたびに呼ばれる
loadedPrefabs.Add(prefab);
Debug.Log($"Loaded: {prefab.name}");
}
);
handle.Completed += OnAllLoaded;
}
void OnAllLoaded(AsyncOperationHandle<IList<GameObject>> op)
{
if (op.Status == AsyncOperationStatus.Succeeded)
{
Debug.Log($"All {op.Result.Count} assets loaded.");
}
}
void OnDestroy()
{
Addressables.Release(handle);
}
}
ラベルの命名規則: ラベル名は小文字のケバブケースまたはスネークケースを推奨します(例:
stage-1-assets、enemy_prefabs)。大文字やスペースは避けてください。
アセットのアンロード
Addressablesでロードしたアセットは、必ずアンロードする必要があります。アンロードしないと、メモリリークが発生します。
// アドレス文字列でロードした場合
Addressables.Release(handle);
// AssetReferenceでロードした場合
assetReference.ReleaseAsset();
Play Modeの使い分け
Addressablesには、3つのPlay Modeがあります。
| Play Mode | 説明 | 用途 |
|---|---|---|
| Use Asset Database (fastest) | AssetDatabaseから直接ロード | 開発中の高速イテレーション |
| Simulate Groups (advanced) | AssetBundleをシミュレート | 依存関係やメモリ管理の確認 |
| Use Existing Build | 実際のAssetBundleを使用 | 本番環境に近い動作確認 |
実践的な使用例
例1:プレハブを動的にロードしてインスタンス化
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class SpawnEnemy : MonoBehaviour
{
public AssetReference enemyPrefab;
private AsyncOperationHandle<GameObject> handle;
void Start()
{
handle = enemyPrefab.LoadAssetAsync<GameObject>();
handle.Completed += OnLoadCompleted;
}
void OnLoadCompleted(AsyncOperationHandle<GameObject> op)
{
if (op.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(op.Result, transform.position, Quaternion.identity);
}
}
void OnDestroy()
{
enemyPrefab.ReleaseAsset();
}
}
例2:シーンを動的にロード
public AssetReference sceneReference;
public void LoadSceneAdditive()
{
sceneReference.LoadSceneAsync(LoadSceneMode.Additive);
}
メモリリークの検出:Event Viewer
Addressablesでは「必ずアンロードする」ことが重要ですが、本当にアンロードできているか確認する方法が必要です。
Addressables Event Viewer を使うと、ロード中のアセットをリアルタイムで確認できます。
Event Viewerの開き方
Window > Asset Management > Addressables > Event Viewerを選択- Play Modeでゲームを実行
- ロード/アンロードの状況がリアルタイムで表示される
確認ポイント
- シーン遷移後にアセットが残っていないか
- 同じアセットが複数回ロードされていないか
- 参照カウントが正しく減少しているか
注意: Event Viewerを使用するには、Addressables設定で「Send Profiler Events」を有効にする必要があります。
ベストプラクティス
- アセットをグループ化する - 関連するアセットは同じグループにまとめる
- ラベルを活用する - 複数のアセットを一度にロードしたい場合に便利
- AssetReferenceを使う - 型安全で、インスペクターでアセットを直接割り当てられる
- 必ずアンロードする -
OnDestroyやOnDisableでアンロードする - Play Modeを使い分ける - 開発中はUse Asset Database、最終確認時はUse Existing Build
- Event Viewerで検証する - メモリリークがないか定期的に確認
まとめ
Addressablesは、Unity公式のアセット管理システムです。AssetBundleをベースにしながら、依存関係の管理、メモリ管理、ロード元の切り替えを自動化します。
- ロード元を簡単に切り替えられる - 設定変更だけで開発用とリリース用を切り替え
- 依存関係を自動的に解決する - 依存するAssetBundleを自動的にロード
- メモリ管理を自動化する - 参照カウンタによる自動メモリ管理
- ダウンロードコンテンツを簡単に配信できる - リモートサーバーからのダウンロードに対応
ぜひ、Addressablesを活用して、効率的なアセット管理を実現してください。