【Unity】ResourcesフォルダからAddressableに切り替える
アドレス指定可能型アセットシステム(Addressable Asset System)
Addressable Asset Systemは、"アドレス “によってアセットをロードする簡単な方法を提供します。コンテンツパックの作成と展開を簡素化することで、アセット管理のオーバーヘッドを処理します。
アドレス指定型アセットシステムは、非同期ロードを使用して、あらゆる場所からのロードと、あらゆる依存関係のコレクションをサポートします。直接参照、従来のアセットバンドル、リソースフォルダのいずれを使用している場合でも、アドレス指定可能なアセットは、ゲームをよりダイナミックにするためのシンプルな方法を提供します。
アセットとは?
アセットとは、ゲームやアプリを作成するために使用するコンテンツのことです。アセットには、プレハブ、テクスチャ、マテリアル、オーディオクリップ、アニメーションなどがあります。
アドレスとは?
アドレスは、何かが存在する場所を特定するものです。例えば、携帯電話に電話をかけると、電話番号が住所として機能します。相手が家にいても、職場にいても、パリにいても、ピッツバーグにいても、電話番号でつながることができるのです。
アドレス指定可能なアセットとは?
あるアセットが「アドレス指定可能(addressable)」とマークされると、そのアドレス指定可能なアセットはどこからでも呼び出すことができるようになります。そのアドレス指定可能なアセットがローカルプレーヤーに存在しようが、コンテンツ配信ネットワークに存在しようが、システムはそれを探し出し返します。アドレスを介して単一のアドレス指定可能なアセットをロードすることも、定義したカスタマイズされたグループラベルを使用して多数のアドレス指定可能なアセットをロードすることも可能です。
なぜ必要になるのか?
従来、コンテンツを効率的にロードするためにゲームアセットを構造化することは困難でした。
アドレス指定可能なアセットを使用すると、反復サイクルが短縮され、アプリケーションの設計、コーディング、およびテストに多くの時間を割くことができるようになります。アドレス指定可能なアセットでは、アセットがアドレス指定可能であることを確認し、それをロードします。
アドレス指定可能なアセットシステムは、どのような問題を解決するのでしょうか?
開発サイクル
アドレスでコンテンツを参照することは、非常に効率的です。アドレスの参照により、コンテンツは単に検索されるだけです。コンテンツを最適化するために、コードを変更する必要はありません。
依存性の管理
アドレスでコンテンツを返すだけでなく、そのコンテンツの依存関係もすべて返します。アセット全体の準備が整った時点で通知されるため、コンテンツが返される前にメッシュ、シェーダー、アニメーションなどがすべてロードされます。
メモリ管理
アドレスはアセットをロードするだけでなく、アンロードも行います。参照は自動的にカウントされ、堅牢なプロファイラーが潜在的なメモリ問題を発見するのに役立ちます。
コンテンツのパッキング
:システムは複雑な依存関係の連鎖をマッピングして理解するため、アセットの移動や名前の変更があっても、バンドルの効率的なパッキングを可能にします。アセットをローカルとリモートの両方に展開することで、ダウンロードコンテンツ(DLC)やアプリケーションサイズの縮小を容易に準備することができます。
既存のゲームの移行ついてはどうですか?
Addressable Asset Systemは、直接参照、Resourceフォルダ、Asset Bundleのいずれを使用しても、アップグレードのための移行経路を提供します。
Resourcesフォルダからの移行
Resourcesサンプルの作成
Addressable Assets packageのインストール
WindowメニューのPackageManagerからAddressablesをインストールします
Resourceフォルダにアセットのサンプルを保存
今回はサンプルとしてプレファブを作っておきます
動的にゲームオブジェクトロードして生成するコード
実行中にリソースフォルダからロードしてシーンに登場させます
using UnityEngine;
public class LoadPrefab : MonoBehaviour
{
void Start()
{
var cube = Resources.Load<GameObject>("Cube");
Instantiate(cube);
}
}
シーンの構成
新しくゲームオブジェクトを作成して、スクリプトをアタッチします
実行結果
アドレス指定可能型アセットシステムへの移行
Cubeプレファブを選択して、Addressableにします
プレファブアセットの保存場所を移動する旨のメッセージが出ますので、Yesを選択します
Resources_movedフォルダが自動作成されてプレファブが移動されています
もちろん、このまま実行してもエラーになります
スクリプトの更新
using UnityEngine;
using UnityEngine.AddressableAssets;
public class LoadPrefab : MonoBehaviour
{
async void Start()
{
var cube = Addressables.LoadAssetAsync<GameObject>("Cube");
await cube.Task;
Instantiate(cube.Result);
}
}
このコードはUnityのAddressable Assetsを使用して、アセットバンドルからプレハブをロードし、インスタンス化する方法を示しています。
using
ステートメントでUnityエンジンとAddressable Assetsをインポートします。
LoadPrefab
クラスはMonoBehaviour
を継承しています。
Start()
メソッドは、UnityのライフサイクルイベントであるStart
時に自動的に呼び出されます。
async
キーワードは、このメソッドが非同期であることを示します。
Addressables.LoadAssetAsync
メソッドは、アセットバンドルから指定されたアセットのロードを開始します。この場合、Cube
プレハブをロードします。
await
キーワードは、ロードが完了するまでcube.Task
が待機することを示します。
Instantiate
メソッドは、ロードされたプレハブをインスタンス化して、シーンに表示します。
したがって、このコードは、アセットバンドルからCube
プレハブを非同期でロードし、完了したらシーンに表示します。
実行結果
移行前と同様、実行時にプレファブからインスタンスが作成されるようになります
おまけ
エラー処理つき
以下は、LoadPrefab
クラスのリファクタリングしたコードです。このコードは、読みやすく保守性が高くなっています。
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class LoadPrefab : MonoBehaviour
{
[SerializeField] private string prefabName;
private async void Start()
{
var prefabHandle = Addressables.LoadAssetAsync<GameObject>(prefabName);
await prefabHandle.Task;
if (prefabHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(prefabHandle.Result);
}
else
{
Debug.LogError($"Failed to load prefab {prefabName}");
}
}
}
このコードでは、以下の点が変更されています。
using
ステートメントにUnityEngine.ResourceManagement.AsyncOperations
が追加されています。これにより、非同期操作の状態を確認できます。Cube
という文字列が、インスペクターから設定可能なprefabName
変数に変更されています。Instantiate
メソッドが条件分岐に入れられ、ロードに失敗した場合はDebug.LogError
を出力するようになっています。
進捗の確認
簡易的なものになりますが参考まで
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class LoadPrefab : MonoBehaviour
{
AsyncOperationHandle<GameObject> cube;
async void Start()
{
StartCoroutine(Progress());
await GetAndCreateCube();
}
private IEnumerator Progress()
{
while (!cube.IsValid())
{
Debug.Log("not");
yield return null;
}
while (true)
{
if (cube.IsDone)
{
break;
}
Debug.Log(cube.GetDownloadStatus().Percent);
yield return null;
}
}
private async Task GetAndCreateCube()
{
cube = Addressables.LoadAssetAsync<GameObject>("Cube");
await cube.Task;
Instantiate(cube.Result);
}
}
ディスカッション
コメント一覧
まだ、コメントがありません