はじめに
「UniTask」を Unity プロジェクトに導入することで
非同期処理を簡単に記述できるようになります
この記事では「UniTask」の使い方をいくつか紹介していきます
目次
- はじめに
- 目次
- 検証環境
- 導入方法
- 使用例
- Resources.Load を非同期で待つ
- シーンの読み込みを非同期で待つ
- 指定したフレーム数待つ
- 指定した秒数待つ
- コルーチンを待つ
- 指定した条件が true になるまで待つ
- 指定した条件が false になるまで待つ
- 自作の非同期メソッドを待つ
- UnityWebRequest を待つ
- 進捗を取得する
- 3D の当たり判定を待つ
- 2D の当たり判定を待つ
- ボタンが押されるのを待つ
- Awake、Start、OnDestroy を待つ
- OnEnable、OnDisable を待つ
- AsyncLazy(非同期遅延初期化)を書く
- すべての非同期処理が終わるまで待つ
- いずれかの非同期処理が終わるまで待つ
検証環境
- Unity 2018.4.8f1
- UniTask 1.1.0
導入方法
https://github.com/Cysharp/UniTask/releases
上記のページから「UniRx.Async.unitypackage」をダウンロードして
Unity プロジェクトにインポートします
使用例
Resources.Load を非同期で待つ
using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { private async void Start() { var sprite = await Resources.LoadAsync<Sprite>( "" ); Debug.Log( sprite.name ); } }
シーンの読み込みを非同期で待つ
using UniRx.Async; using UnityEngine; using UnityEngine.SceneManagement; public sealed class Example : MonoBehaviour { private async void Start() { await SceneManager.LoadSceneAsync( "" ); Debug.Log( "完了" ); } }
指定したフレーム数待つ
using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { private async void Start() { await UniTask.DelayFrame( 25 ); Debug.Log( "完了" ); } }
指定した秒数待つ
using System; using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { private async void Start() { await UniTask.Delay( TimeSpan.FromSeconds( 3 ) ); // Time.timeScale を無視する場合 await UniTask.Delay( TimeSpan.FromSeconds( 3 ), true ); Debug.Log( "完了" ); } }
コルーチンを待つ
using System.Collections; using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { private async void Start() { await Hoge(); Debug.Log( "完了" ); } private IEnumerator Hoge() { yield break; } }
指定した条件が true になるまで待つ
using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { private bool m_isStart; private async void Start() { await UniTask.WaitUntil( () => m_isStart ); Debug.Log( "完了" ); } private void Update() { if ( Input.GetKeyDown( KeyCode.Space ) ) { m_isStart = true; } } }
指定した条件が false になるまで待つ
using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { private bool m_isStop = true; private async void Start() { await UniTask.WaitWhile( () => m_isStop ); Debug.Log( "完了" ); } private void Update() { if ( Input.GetKeyDown( KeyCode.Space ) ) { m_isStop = false; } } }
自作の非同期メソッドを待つ
using System; using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { private async void Start() { var result = await Hoge(); Debug.Log( result ); } private async UniTask<string> Hoge() { // 3 秒待つ await UniTask.Delay( TimeSpan.FromSeconds( 3 ) ); return await UniTask.Run( () => "完了" ); } }
UnityWebRequest を待つ
using UniRx.Async; using UnityEngine; using UnityEngine.Networking; public sealed class Example : MonoBehaviour { private async void Start() { var url = "http://baba-s.hatenablog.com/"; var request = UnityWebRequest.Get( url ); await request.SendWebRequest(); Debug.Log( request.downloadHandler.text ); } }
進捗を取得する
using System; using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { private async void Start() { var sprite = await Resources .LoadAsync<Sprite>( "" ) .ConfigureAwait( new Progress<float>( p => Debug.Log( p ) ) ) ; Debug.Log( sprite.name ); } }
ConfigureAwait を使用することで非同期処理の進捗を取得できます
3D の当たり判定を待つ
using UniRx.Async.Triggers; using UnityEngine; public sealed class Example : MonoBehaviour { private async void Start() { var trigger = this.GetAsyncCollisionTrigger(); // OnCollisionEnter を待つ var result = await trigger.OnCollisionEnterAsync(); // OnCollisionStay を待つ //var result = await trigger.OnCollisionStayAsync(); // OnCollisionExit を待つ //var result = await trigger.OnCollisionExitAsync(); Debug.Log( result.gameObject.name ); } }
2D の当たり判定を待つ
using UniRx.Async.Triggers; using UnityEngine; public sealed class Example : MonoBehaviour { private async void Start() { var trigger = this.GetAsyncCollision2DTrigger(); // OnCollisionEnter2D を待つ var result = await trigger.OnCollisionEnter2DAsync(); // OnCollisionStay2D を待つ //var result = await trigger.OnCollisionStay2DAsync(); // OnCollisionExit2D を待つ //var result = await trigger.OnCollisionExit2DAsync(); Debug.Log( result.gameObject.name ); } }
ボタンが押されるのを待つ
using UniRx.Async; using UnityEngine; using UnityEngine.UI; public sealed class Example : MonoBehaviour { public Button m_button; private async void Start() { await m_button.OnClickAsync(); Debug.Log( "完了" ); } }
Awake、Start、OnDestroy を待つ
using UniRx.Async.Triggers; using UnityEngine; public sealed class Example : MonoBehaviour { public GameObject m_target; private async void Start() { await m_target.AwakeAsync(); Debug.Log( "Awake" ); await m_target.StartAsync(); Debug.Log( "Start" ); await m_target.OnDestroyAsync(); Debug.Log( "OnDestroy" ); } }
OnEnable、OnDisable を待つ
using UniRx.Async.Triggers; using UnityEngine; public sealed class Example : MonoBehaviour { public GameObject m_target; private async void Start() { var trigger = m_target.GetAsyncEnableDisableTrigger(); await trigger.OnEnableAsync(); Debug.Log( "OnEnable" ); await trigger.OnDisableAsync(); Debug.Log( "OnDisable" ); } }
AsyncLazy(非同期遅延初期化)を書く
using UniRx.Async; using UnityEngine; public sealed class Example : MonoBehaviour { public UniTask<TextAsset> TextAsset { get; } = UniTask.Lazy( () => LoadTextAsset() ); private async void Start() { var textAsset1 = await TextAsset; // 1回目は非同期処理が実行される var textAsset2 = await TextAsset; // 2回目以降は結果のみが取得される var textAsset3 = await TextAsset; } private static async UniTask<TextAsset> LoadTextAsset() { // 1回だけログが出力される Debug.Log( "初期化" ); var textAsset = await Resources.LoadAsync<TextAsset>( "text" ); return textAsset as TextAsset; } }
すべての非同期処理が終わるまで待つ
戻り値なし
using UniRx.Async; using UnityEngine; using UnityEngine.UI; public sealed class Example : MonoBehaviour { public Button m_button1; public Button m_button2; public Button m_button3; private async void Start() { var onClick1 = m_button1.OnClickAsync(); var onClick2 = m_button2.OnClickAsync(); var onClick3 = m_button3.OnClickAsync(); // すべてのボタンが押されるまで待つ await UniTask.WhenAll( onClick1, onClick2, onClick3 ); Debug.Log( "完了" ); } }
戻り値あり
using UniRx.Async; using UnityEngine; using UnityEngine.Networking; public sealed class Example : MonoBehaviour { private async void Start() { async UniTask<string> GetTextAsync( UnityWebRequest request ) { var operation = await request.SendWebRequest(); return operation.downloadHandler.text; } var task1 = GetTextAsync( UnityWebRequest.Get( "http://google.com" ) ); var task2 = GetTextAsync( UnityWebRequest.Get( "http://bing.com" ) ); var task3 = GetTextAsync( UnityWebRequest.Get( "http://yahoo.com" ) ); // すべての通信が完了するまで待つ var (unity, github, yahoo) = await UniTask.WhenAll( task1, task2, task3 ); //var result = await UniTask.WhenAll( task1, task2, task3 ); Debug.Log( "完了" ); } }
いずれかの非同期処理が終わるまで待つ
戻り値なし
using UniRx.Async; using UnityEngine; using UnityEngine.UI; public sealed class Example : MonoBehaviour { public Button m_button1; public Button m_button2; public Button m_button3; private async void Start() { var onClick1 = m_button1.OnClickAsync(); var onClick2 = m_button2.OnClickAsync(); var onClick3 = m_button3.OnClickAsync(); // いずれかのボタンが押されるまで待つ await UniTask.WhenAny( onClick1, onClick2, onClick3 ); Debug.Log( "完了" ); } }
戻り値あり
using UniRx.Async; using UnityEngine; using UnityEngine.Networking; public sealed class Example : MonoBehaviour { private async void Start() { async UniTask<string> GetTextAsync( UnityWebRequest request ) { var operation = await request.SendWebRequest(); return operation.downloadHandler.text; } var task1 = GetTextAsync( UnityWebRequest.Get( "http://google.com" ) ); var task2 = GetTextAsync( UnityWebRequest.Get( "http://bing.com" ) ); var task3 = GetTextAsync( UnityWebRequest.Get( "http://yahoo.com" ) ); // いずれかの通信が完了するまで待つ var (unity, github, yahoo) = await UniTask.WhenAll( task1, task2, task3 ); //var result = await UniTask.WhenAny( task1, task2, task3 ); Debug.Log( "完了" ); } }