「Unity/UniTask」の版間の差分
(ページの作成:「==ダウンロード== https://github.com/Cysharp/UniTask/releases ==サンプル== ==参考== https://qiita.com/toRisouP/items/4445b6b9bf00e49eb147」) |
(→関数を2つ以上挟む) |
||
(同じ利用者による、間の51版が非表示) | |||
行1: | 行1: | ||
==ダウンロード== | ==ダウンロード== | ||
+ | ===PackageManagerでインストール=== | ||
+ | #Unityメインメニュー/Window/PackageManager/右上の+ | ||
+ | #Add package from git URL | ||
+ | |||
+ | https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask | ||
+ | |||
+ | ===unitypackageでインストール=== | ||
https://github.com/Cysharp/UniTask/releases | https://github.com/Cysharp/UniTask/releases | ||
+ | |||
+ | UniTask.2.2.5.unitypackageをDLしてインストール | ||
+ | |||
+ | ==ScriptableSingletonエラーが出る時== | ||
+ | ScriptableSingleton already exists. Did you query the singleton in a constructor? UnityEditor.PackageManager.UI.PackageManagerProjectSettings:.ctor () (at /Users/bokken/buildslave/unity/build/Modules/PackageManagerUI/Editor/Services/ProjectSettings/PackageManagerProjectSettings.cs:102) | ||
+ | |||
+ | がでるときは、Pluginsに直接、csをインストールしてないか確認、unitypackageからインストールしてみる。 | ||
+ | |||
+ | ==Taskとの比較== | ||
+ | UniTaskは、Taskより軽く、SynchronizationContextへの依存がない。 | ||
+ | |||
+ | Taskサンプルはこちら | ||
+ | |||
+ | [[Unity/Csharp/別スレッド]] [ショートカット] | ||
==サンプル== | ==サンプル== | ||
+ | <pre> | ||
+ | using System.Collections; | ||
+ | using System.Collections.Generic; | ||
+ | using UnityEngine; | ||
+ | using System.Threading.Tasks; // Taskサンプル用 | ||
+ | // using UniRx.Async; // UniTask ver1 | ||
+ | using Cysharp.Threading.Tasks; // UniTask ver2 | ||
+ | public class SampleScene : MonoBehaviour | ||
+ | { | ||
+ | void Start() | ||
+ | { | ||
+ | Exec(); | ||
+ | } | ||
+ | async void Exec() | ||
+ | { | ||
+ | var result = await ExecUniTask(); | ||
+ | Debug.Log("Exec " + result); // Exec Hello!! | ||
+ | } | ||
+ | async UniTask<string> ExecUniTask() | ||
+ | { | ||
+ | return await Task.Run(() => "Hello!!"); | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | ==IEnumeratorが戻り値のものを実行== | ||
+ | UniTaskだと、IEnumeratorのものを、StartCoroutineではなくてawaitで実行できる。 | ||
+ | <pre> | ||
+ | using Cysharp.Threading.Tasks; | ||
+ | public class SampleScene : MonoBehaviour | ||
+ | { | ||
+ | void Start() | ||
+ | { | ||
+ | ExecInvoke(); | ||
+ | } | ||
+ | async void ExecInvoke() | ||
+ | { | ||
+ | await DelayMethod1(5.0f, 123); | ||
+ | } | ||
+ | IEnumerator DelayMethod1(float delay, int hoge) | ||
+ | { | ||
+ | yield return new WaitForSeconds(delay); | ||
+ | // ここに処理を追加 | ||
+ | Debug.Log("DelayMethod1 exec " + hoge); | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | ==マルチスレッド== | ||
+ | <pre> | ||
+ | public class MultiThreadScene : MonoBehaviour | ||
+ | { | ||
+ | async void Start() | ||
+ | { | ||
+ | await ExecAsync(); | ||
+ | } | ||
+ | |||
+ | async UniTask ExecAsync() | ||
+ | { | ||
+ | await UniTask.SwitchToThreadPool(); // 別スレッドへ | ||
+ | |||
+ | // ここに処理記述 | ||
+ | Debug.Log(Thread.CurrentThread.ManagedThreadId); | ||
+ | |||
+ | await UniTask.SwitchToMainThread(); // メインスレッドに戻す | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | 参考:https://light11.hatenadiary.com/entry/2021/05/27/203956 | ||
+ | |||
+ | ==ボタンを押して処理== | ||
+ | <pre> | ||
+ | void Start() | ||
+ | { | ||
+ | cacheButton.onClick.AddListener(async () => { await ExecDel(); }); | ||
+ | } | ||
+ | async void ExecDel() | ||
+ | { | ||
+ | } | ||
+ | </pre> | ||
+ | ==条件を満たしたら先へ== | ||
+ | <pre> | ||
+ | async void Exec() | ||
+ | { | ||
+ | await UniTask.WaitUntil(() => transform.position.y < 0); | ||
+ | Debug.Log("ok"); | ||
+ | } | ||
+ | </pre> | ||
+ | MainCameraにaddComponentしてたら、Yの値を-1にすると先へ進む | ||
+ | |||
+ | ==入力待機== | ||
+ | <pre> | ||
+ | using UnityEngine; | ||
+ | using Cysharp.Threading.Tasks; | ||
+ | public class WaitScene : MonoBehaviour | ||
+ | { | ||
+ | void Start() | ||
+ | { | ||
+ | WaitInput(); | ||
+ | } | ||
+ | async void WaitInput() | ||
+ | { | ||
+ | await UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Return)); | ||
+ | // await UniTask.WaitWhile(() => !Input.GetKeyDown(KeyCode.Return)); // 条件に当てはまらないときは、先にすすめる | ||
+ | // ここに処理を追加 | ||
+ | Debug.Log("return!!"); | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | ==数秒待つ== | ||
+ | <pre> | ||
+ | async void Hoge() { | ||
+ | await UniTask.Delay(100); // ms | ||
+ | } | ||
+ | </pre> | ||
+ | Invokeとかと違って、シーンが変更されても実行されるので気をつける。 | ||
+ | |||
+ | ==呼び出し元も待つように== | ||
+ | <pre> | ||
+ | async void Main() { | ||
+ | Debug.Log("start"); | ||
+ | await Hoge(); | ||
+ | Debug.Log("end"); // 0.1秒後に表示される | ||
+ | } | ||
+ | async UniTask Hoge() { | ||
+ | await UniTask.Delay(100); // ms | ||
+ | } | ||
+ | </pre> | ||
+ | ===UniTask.Delayのキャンセル=== | ||
+ | <pre> | ||
+ | using Cysharp.Threading.Tasks; | ||
+ | using System.Threading; | ||
+ | |||
+ | CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); | ||
+ | CancellationToken cancellationToken = cancellationTokenSource.Token; | ||
+ | ViewCntCancelAsync(cancellationToken); | ||
+ | cancellationTokenSource.Cancel(); | ||
+ | async void ViewCntCancelAsync(CancellationToken cancellationToken) | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | await UniTask.Delay(3000, cancellationToken: cancellationToken); | ||
+ | } | ||
+ | catch (OperationCanceledException e) | ||
+ | { | ||
+ | Debug.LogWarning("Canceled!"); | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | 参考:https://qiita.com/su10/items/ccb12742ad0be790b323 | ||
+ | |||
+ | ==関数を2つ以上挟む== | ||
+ | <pre> | ||
+ | async void Hoge() { | ||
+ | await Hoge2(); | ||
+ | } | ||
+ | async UniTask<float> Hoge2() { | ||
+ | await UniTask.Delay(100); // ms | ||
+ | await UniTask.Delay(100); // ms | ||
+ | return 200f; | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | ↓数値で指定しない場合 | ||
+ | <pre> | ||
+ | async void Hoge() { | ||
+ | await Hoge2(); | ||
+ | } | ||
+ | async UniTask Hoge2() { | ||
+ | await UniTask.Delay(100); // ms | ||
+ | await UniTask.Delay(100); // ms | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | ==並列処理== | ||
+ | <pre> | ||
+ | using UnityEngine; | ||
+ | using Cysharp.Threading.Tasks; | ||
+ | public class WhenAllScene : MonoBehaviour | ||
+ | { | ||
+ | async void Start() | ||
+ | { | ||
+ | await UniTask.WhenAll(HogeAsync(), HogeAsync(), HogeAsync()); | ||
+ | |||
+ | } | ||
+ | async UniTask HogeAsync() | ||
+ | { | ||
+ | Debug.Log("HogeAsync"); | ||
+ | await UniTask.Delay(1000); // ms | ||
+ | Debug.Log("HogeAsyncEnd"); | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | HogeAsyncがまとめて3回表示されて、一秒後に、HogeAsyncEndが3回表示される。 | ||
+ | |||
+ | 参考:https://light11.hatenadiary.com/entry/2021/05/27/203956 | ||
+ | |||
+ | ===tasksでまとめて、すべて処理する=== | ||
+ | <pre> | ||
+ | var tasks = new List<UniTask>(); | ||
+ | tasks.Add(HogeAsync()); | ||
+ | tasks.Add(HogeAsync()); | ||
+ | tasks.Add(HogeAsync()); | ||
+ | await UniTask.WhenAll(tasks); | ||
+ | </pre> | ||
+ | |||
+ | ===DelayとWaitUntilのどちらか=== | ||
+ | 数秒待つか、条件を満たすか、どちらかを満たすとき、処理を通す | ||
+ | <pre> | ||
+ | await UniTask.WhenAny( | ||
+ | UniTask.Delay(10000), | ||
+ | UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Return)) | ||
+ | ); | ||
+ | </pre> | ||
+ | キャンセル処理 | ||
+ | <pre> | ||
+ | var cancellationTokenSource = new CancellationTokenSource(); | ||
+ | await UniTask.WhenAny( | ||
+ | UniTask.Delay(10000, cancellationToken : cancellationTokenSource.Token), | ||
+ | UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Return), cancellationToken : cancellationTokenSource.Token) | ||
+ | ); | ||
+ | cancellationTokenSource.Cancel(); | ||
+ | </pre> | ||
+ | |||
+ | キャンセル処理、関数化 | ||
+ | <pre> | ||
+ | async UniTask DelayWaitUntil(int delayMs, Func<bool> cond) | ||
+ | { | ||
+ | cancellationTokenSource = new CancellationTokenSource(); | ||
+ | await UniTask.WhenAny( | ||
+ | UniTask.Delay(delayMs, cancellationToken: cancellationTokenSource.Token), | ||
+ | UniTask.WaitUntil(cond, cancellationToken: cancellationTokenSource.Token) | ||
+ | ); | ||
+ | } | ||
+ | // 関数コール | ||
+ | await DelayWaitUntil(1000, () => Input.GetKeyDown(KeyCode.Return)); | ||
+ | // キャンセルしたい時に実行 | ||
+ | cancellationTokenSource.Cancel(); | ||
+ | </pre> | ||
+ | 参考:https://blog.gigacreation.jp/entry/2019/11/08/141305 | ||
+ | |||
+ | ==="OperationCanceledException: The operation was canceled. "エラーを出さないようにする場合=== | ||
+ | try-catchを使う | ||
+ | <pre> | ||
+ | try | ||
+ | { | ||
+ | cancellationTokenSource = new CancellationTokenSource(); | ||
+ | await UniTask.WhenAny( | ||
+ | UniTask.Delay(delayMs, cancellationToken: cancellationTokenSource.Token), | ||
+ | UniTask.WaitUntil(cond, cancellationToken: cancellationTokenSource.Token) | ||
+ | ); | ||
+ | } | ||
+ | catch (OperationCanceledException) | ||
+ | { | ||
+ | Debug.LogWarning("DelayCanceled!"); | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | ==インターフェイスの書き方== | ||
+ | asyncを使ったときの例 | ||
+ | <pre> | ||
+ | using Cysharp.Threading.Tasks; | ||
+ | public class HogeUseCase : HogeDelegate | ||
+ | public async UniTask Leave() | ||
+ | { | ||
+ | // 処理 | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | <pre> | ||
+ | using Cysharp.Threading.Tasks; | ||
+ | public interface HogeDelegate | ||
+ | { | ||
+ | UniTask Leave(); | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | ==UniTaskVoidという型== | ||
+ | asyncで、voidを返す場合は、UniTaskのvoidということで、UniTaskVoidという型がある。 | ||
+ | UniTaskVoidのほうが明示的なので、よいかも。 | ||
+ | <pre> | ||
+ | - async void Hoge() {} | ||
+ | + async UniTaskVoid Hoge() {} | ||
+ | </pre> | ||
+ | |||
+ | ===UniTaskVoidサンプル=== | ||
+ | using Cysharp.Threading.Tasks; | ||
+ | <pre> | ||
+ | async void Start() | ||
+ | { | ||
+ | Test(); | ||
+ | } | ||
+ | async UniTaskVoid Test() | ||
+ | { | ||
+ | } | ||
+ | </pre> | ||
==参考== | ==参考== | ||
+ | UniTask使い方 | ||
https://qiita.com/toRisouP/items/4445b6b9bf00e49eb147 | https://qiita.com/toRisouP/items/4445b6b9bf00e49eb147 | ||
+ | |||
+ | UniTask ver2 | ||
+ | https://qiita.com/toRisouP/items/8f66fd952eaffeaf3107 |
2024年7月29日 (月) 19:48時点における最新版
目次
ダウンロード
PackageManagerでインストール
- Unityメインメニュー/Window/PackageManager/右上の+
- Add package from git URL
https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
unitypackageでインストール
https://github.com/Cysharp/UniTask/releases
UniTask.2.2.5.unitypackageをDLしてインストール
ScriptableSingletonエラーが出る時
ScriptableSingleton already exists. Did you query the singleton in a constructor? UnityEditor.PackageManager.UI.PackageManagerProjectSettings:.ctor () (at /Users/bokken/buildslave/unity/build/Modules/PackageManagerUI/Editor/Services/ProjectSettings/PackageManagerProjectSettings.cs:102)
がでるときは、Pluginsに直接、csをインストールしてないか確認、unitypackageからインストールしてみる。
Taskとの比較
UniTaskは、Taskより軽く、SynchronizationContextへの依存がない。
Taskサンプルはこちら
Unity/Csharp/別スレッド [ショートカット]
サンプル
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Threading.Tasks; // Taskサンプル用 // using UniRx.Async; // UniTask ver1 using Cysharp.Threading.Tasks; // UniTask ver2 public class SampleScene : MonoBehaviour { void Start() { Exec(); } async void Exec() { var result = await ExecUniTask(); Debug.Log("Exec " + result); // Exec Hello!! } async UniTask<string> ExecUniTask() { return await Task.Run(() => "Hello!!"); } }
IEnumeratorが戻り値のものを実行
UniTaskだと、IEnumeratorのものを、StartCoroutineではなくてawaitで実行できる。
using Cysharp.Threading.Tasks; public class SampleScene : MonoBehaviour { void Start() { ExecInvoke(); } async void ExecInvoke() { await DelayMethod1(5.0f, 123); } IEnumerator DelayMethod1(float delay, int hoge) { yield return new WaitForSeconds(delay); // ここに処理を追加 Debug.Log("DelayMethod1 exec " + hoge); } }
マルチスレッド
public class MultiThreadScene : MonoBehaviour { async void Start() { await ExecAsync(); } async UniTask ExecAsync() { await UniTask.SwitchToThreadPool(); // 別スレッドへ // ここに処理記述 Debug.Log(Thread.CurrentThread.ManagedThreadId); await UniTask.SwitchToMainThread(); // メインスレッドに戻す } }
参考:https://light11.hatenadiary.com/entry/2021/05/27/203956
ボタンを押して処理
void Start() { cacheButton.onClick.AddListener(async () => { await ExecDel(); }); } async void ExecDel() { }
条件を満たしたら先へ
async void Exec() { await UniTask.WaitUntil(() => transform.position.y < 0); Debug.Log("ok"); }
MainCameraにaddComponentしてたら、Yの値を-1にすると先へ進む
入力待機
using UnityEngine; using Cysharp.Threading.Tasks; public class WaitScene : MonoBehaviour { void Start() { WaitInput(); } async void WaitInput() { await UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Return)); // await UniTask.WaitWhile(() => !Input.GetKeyDown(KeyCode.Return)); // 条件に当てはまらないときは、先にすすめる // ここに処理を追加 Debug.Log("return!!"); } }
数秒待つ
async void Hoge() { await UniTask.Delay(100); // ms }
Invokeとかと違って、シーンが変更されても実行されるので気をつける。
呼び出し元も待つように
async void Main() { Debug.Log("start"); await Hoge(); Debug.Log("end"); // 0.1秒後に表示される } async UniTask Hoge() { await UniTask.Delay(100); // ms }
UniTask.Delayのキャンセル
using Cysharp.Threading.Tasks; using System.Threading; CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); CancellationToken cancellationToken = cancellationTokenSource.Token; ViewCntCancelAsync(cancellationToken); cancellationTokenSource.Cancel(); async void ViewCntCancelAsync(CancellationToken cancellationToken) { try { await UniTask.Delay(3000, cancellationToken: cancellationToken); } catch (OperationCanceledException e) { Debug.LogWarning("Canceled!"); } }
参考:https://qiita.com/su10/items/ccb12742ad0be790b323
関数を2つ以上挟む
async void Hoge() { await Hoge2(); } async UniTask<float> Hoge2() { await UniTask.Delay(100); // ms await UniTask.Delay(100); // ms return 200f; }
↓数値で指定しない場合
async void Hoge() { await Hoge2(); } async UniTask Hoge2() { await UniTask.Delay(100); // ms await UniTask.Delay(100); // ms }
並列処理
using UnityEngine; using Cysharp.Threading.Tasks; public class WhenAllScene : MonoBehaviour { async void Start() { await UniTask.WhenAll(HogeAsync(), HogeAsync(), HogeAsync()); } async UniTask HogeAsync() { Debug.Log("HogeAsync"); await UniTask.Delay(1000); // ms Debug.Log("HogeAsyncEnd"); } }
HogeAsyncがまとめて3回表示されて、一秒後に、HogeAsyncEndが3回表示される。
参考:https://light11.hatenadiary.com/entry/2021/05/27/203956
tasksでまとめて、すべて処理する
var tasks = new List<UniTask>(); tasks.Add(HogeAsync()); tasks.Add(HogeAsync()); tasks.Add(HogeAsync()); await UniTask.WhenAll(tasks);
DelayとWaitUntilのどちらか
数秒待つか、条件を満たすか、どちらかを満たすとき、処理を通す
await UniTask.WhenAny( UniTask.Delay(10000), UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Return)) );
キャンセル処理
var cancellationTokenSource = new CancellationTokenSource(); await UniTask.WhenAny( UniTask.Delay(10000, cancellationToken : cancellationTokenSource.Token), UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Return), cancellationToken : cancellationTokenSource.Token) ); cancellationTokenSource.Cancel();
キャンセル処理、関数化
async UniTask DelayWaitUntil(int delayMs, Func<bool> cond) { cancellationTokenSource = new CancellationTokenSource(); await UniTask.WhenAny( UniTask.Delay(delayMs, cancellationToken: cancellationTokenSource.Token), UniTask.WaitUntil(cond, cancellationToken: cancellationTokenSource.Token) ); } // 関数コール await DelayWaitUntil(1000, () => Input.GetKeyDown(KeyCode.Return)); // キャンセルしたい時に実行 cancellationTokenSource.Cancel();
参考:https://blog.gigacreation.jp/entry/2019/11/08/141305
"OperationCanceledException: The operation was canceled. "エラーを出さないようにする場合
try-catchを使う
try { cancellationTokenSource = new CancellationTokenSource(); await UniTask.WhenAny( UniTask.Delay(delayMs, cancellationToken: cancellationTokenSource.Token), UniTask.WaitUntil(cond, cancellationToken: cancellationTokenSource.Token) ); } catch (OperationCanceledException) { Debug.LogWarning("DelayCanceled!"); }
インターフェイスの書き方
asyncを使ったときの例
using Cysharp.Threading.Tasks; public class HogeUseCase : HogeDelegate public async UniTask Leave() { // 処理 } }
using Cysharp.Threading.Tasks; public interface HogeDelegate { UniTask Leave(); }
UniTaskVoidという型
asyncで、voidを返す場合は、UniTaskのvoidということで、UniTaskVoidという型がある。 UniTaskVoidのほうが明示的なので、よいかも。
- async void Hoge() {} + async UniTaskVoid Hoge() {}
UniTaskVoidサンプル
using Cysharp.Threading.Tasks;
async void Start() { Test(); } async UniTaskVoid Test() { }
参考
UniTask使い方 https://qiita.com/toRisouP/items/4445b6b9bf00e49eb147
UniTask ver2 https://qiita.com/toRisouP/items/8f66fd952eaffeaf3107