Addressable Asset SystemでシーンをLoadした時の戻り値はAsyncOperationHandle<T>
です。LoadSceneAsync()
で返ってくるのと違うので、以下はどうやったらよいのやら。
- 自動的にアクティブにならないように読み込んだシーンをアクティブにする方法
- 通信エラーを考慮した処理の組み立て方
ということで調べたことのメモです。まずは以下を読んでみました。
目次
意訳
AsyncOperationHandle
構造体は、Addressablesの色々なAPIの戻り値で利用されます。主に、アクセス状況や結果にアクセスするのに使われます。処理結果は、AsyncOperationHandle.Release()
を呼んだり、Unloadするまで残ります。
処理が完了すると、AsyncOperationHandle.Status
がAsyncOperationStatus.Succeeded
(成功)かAsyncOperationStatus.Failed
(失敗)になります。成功していたら、AsyncOperationHandle.Result
を通じて処理の結果にアクセスできます。
処理が完了したかどうかはStatusをチェックするか、AsyncOperationHandle.Complete
を使って処理が完了した時に呼び出すコールバックを登録します。
AsyncOperationHandleが返したAddressablesAPIにアクセスするためのリソースが不要になったら、Addressables.Release
メソッドを呼び出して解放します。詳しくはこちら( Custom Operations | Package Manager UI website )。
Typed vs Typeless
多くのAddressables APIは、ジェネリックなAsyncOperationHandle<T>
を返します。これにより、AsyncOperationHandle.Completed
イベントのAsyncOperationHandle.Result
の型を指定して安全に扱えます。一方、非ジェネリックのAsyncOperationHandle
もあります。ジェネリックと非ジェネリックはコンバートして相互に利用できます。ただし、もし非ジェネリックなハンドルを、異なる型のジェネリックにキャストすると実行時に例外エラーが発生します。
読み込み完了のイベント例
AsyncOperationHandle.Completed
を使って読み込み完了時に呼び出すコールバックを登録する例です。
private void TextureHandle_Completed(AsyncOperationHandle<Texture2D> handle) { if (handle.Status == AsyncOperationStatus.Succeeded) { Texture2D result = handle.Result; // これ以降、Textureを利用できます } } void Start() { AsyncOperationHandle<Texture2D> textureHandle = Addressables.LoadAsset<Texture2D>("mytexture"); textureHandle.Completed += TextureHandle_Completed; }
AsyncOperationHandleが返すIEnumeratorで待つ
AsyncOperationHandle
はIEnumerator
を返すので、コルーチンで読み込みの完了を待つことができます。
public IEnumerator Start() { AsyncOperationHandle<Texture2D> handle = Addressables.Load<Texture2D>("mytexture"); yield return handle; if (handle.Status == AsyncOperationStatus.Succeeded) { Texture2D texture = handle.Result; // 以降、Textureが使えます // Textureの利用が終わったら、リソースを解放します Addressables.Release(handle); } }
Async awaitで待つ
AsyncOperationHandle.Task
プロパティーを使って、Async awaitで処理を待つこともできます。
public async Start() { AsyncOperationHandle<Texture2D> handle = Addressables.Load<Texture2D>("mytexture"); await handle.Task; if (handle.Status == AsyncOperationStatus.Succeeded) { Texture2D texture = handle.Result; // 以降、Textureが使えます // Textureの利用が終わったらリソースを解放します Addressables.Release(handle); } }
意訳、以上。
シーンを有効にするには
AsyncOperationHandleの説明には載っていませんでした。スクリプトマニュアルの方にありました。
読み込みが完了した時に渡されるSceneInstance
が持つActivate()
メソッドを、読み込みたくなったタイミングで呼び出せばシーンを有効にできるそうです。
おまけ。LoadSceneAsync()
の定義と引数について。
public static AsyncOperationHandle<SceneInstance> LoadSceneAsync(object key, LoadSceneMode loadMode = null, bool activateOnLoad = true, int priority = 100)
Type | Name | 説明 |
---|---|---|
System.Object | key | 読み込むシーンを指定するAsset Addressです。 |
LoadSceneMode | loadMode | 読み込みモードです。LoadSceneMode.Single なら、全てのシーンを閉じてから新しいシーンを読み込みます。LoadSceneMode.Additive なら、現在のシーンはそのままに新しいシーンを追加読み込みしてマルチシーンにします。 |
System.Boolean | activateOnLoad | falseにするとシーンの読み込みが完了しても自動的には有効になりません。バックグラウンドでシーンを読み込みたい時などに利用します。有効にしたいタイミングで、SceneInstanceのActivate() メソッドを呼び出すことで有効にできます。 |
System.Int32 | priority | シーン読み込みの非同期処理における優先順位を指定します。 |
第1引数がIResourceLocation
でシーンを渡すメソッドもあります。
メモリ管理について
Memory Mangement | Package Manager UI website より。
LoadとUnloadをセットで正しく呼び出せば使用していたメモリーは正しく解放されます。SceneLoadingについては、Addressables.UnloadSceneAsync()
メソッドに解放したいシーンを渡して解放するか、Single
モードで別のシーンを読み込むと前のシーンとハンドルが両方解放されます。
補足
Addressables.UnloadSceneAsync()
の第2引数にfalse
を渡すと、シーンをUnloadしても、ハンドルは解放しなくなります。シーンを再利用したい時などに利用するためのもののようです。迂闊に使わない方がよさそうです。
まとめ
以上でおおよそ把握できました。シーンをバックグラウンドで読み込んであとでアクティブにするには、読み込み時にactivateOnLoad
をfalse
にしてシーンを読み込んで、読み込みが完了した時に返されるSceneInstance
のActivate()
を呼び出せばシーンを有効にできます。
エラー処理は、処理の完了を待って、戻り値のStatus
で成功と失敗を見分けます。
シーンの読み込みと解放については、シーンを切り替える際にAddressables.UnloadSceneAsync()
で追加シーンを解放するか、Single
モードで新しいシーンを読み込みます。
こんな感じでいけそうです。