はじめに
Unite 2018のそろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説にて、Addressable Asset System
という新アセット管理システムの概要が発表されました。
今回はこの新アセットシステム中で用いられるリソース読み込み「Addressables.Instantiate
」をawait
できるようにしてみます。
Addressables.Instantiate の戻り値
Addressables.Instantiate<T>
の戻り値をみたところ、UnityEngine.ResourceManagement.IAsyncOperation<T>
型が使われていました。
public static IAsyncOperation<TObject> Instantiate<TObject>(IResourceLocation location, Transform parent = null, bool instantiateInWorldSpace = false) where TObject : Object
そのためこのIAsyncOperation<T>
をawaitable
にしてあげればよさそうです。
実装
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using UnityEngine.ResourceManagement;
public static class IAsyncOperationExtensions
{
public static TaskAwaiter<T> GetAwaiter<T>(this IAsyncOperation<T> ap)
{
var tcs = new TaskCompletionSource<T>();
ap.Completed += operation => tcs.TrySetResult(operation.Result);
return tcs.Task.GetAwaiter();
}
}
対象をawait
する場合、そのオブジェクトにGetAwaiter
メソッドが生えていればよいためこれを拡張メソッドで追加します。
メソッド内部でTaskCompletionSource
を使って非同期処理をTask
に変換し、そのTaskAwaiter
を返すことでawait
できるようにしています。
使用例
using UnityEngine;
using UnityEngine.AddressableAssets;
public class AddressableTest : MonoBehaviour
{
[SerializeField] private AssetReference _assetReference;
private GameObject _target;
async void Start()
{
_target = await Addressables.Instantiate<GameObject>(null);
}
void Update()
{
if (_target != null)
{
_target.transform.Rotate(90f * Time.deltaTime, 90f * Time.deltaTime, 90f * Time.deltaTime);
}
}
}
まとめ
- 対象のオブジェクトに
GetAwaiter
メソッドさえあればawait対象になる - そのときに
await
管理用のオブジェクトを返す必要があるが、TaskCompletionSource
を使えば簡単に生成できる。