facebook twitter hatena line email

「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でインストール

  1. Unityメインメニュー/Window/PackageManager/右上の+
  2. 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