【Unity】UniTaskの完了をフラグで待ってみる

はじめに

今回はUniTaskの完了をフラグで待機する処理を紹介します

環境は Unity 2021.3.25f1です

やり方

Taskが完了しているかはIsCompletedで取得することができます

using UnityEngine;
using Cysharp.Threading.Tasks;
using System.Threading;
public class Test : MonoBehaviour
{
     void Start()
    {
        Application.targetFrameRate = 60;
    }

    async UniTaskVoid Update()
    {
        if(Input.GetKeyDown(KeyCode.F))
        {
            var task = TestFnuc(this.GetCancellationTokenOnDestroy()).AttachExternalCancellation(this.GetCancellationTokenOnDestroy());//TestFnuc起動
        
            int frame = 0;
            //TestFnucが終わるまで待機  
            //他の記述方法としては下記のやり方がある
            //task.GetAwaiter().IsCompleted
            //task.Status != UniTaskStatus.Succeeded
            while (!task.Status.IsCompleted())
            {
                await UniTask.Yield(cancellationToken: this.GetCancellationTokenOnDestroy());//これがないと同期的な処理になってUnityが止まるので注意
                Debug.Log("TestFnuc実行中 frame[" + frame.ToString() + "]");
                frame++;
            }
         
        }
    }

    async UniTask TestFnuc(CancellationToken Token)
    {
        Token.ThrowIfCancellationRequested();
        Debug.Log("TestFnuc開始");
        await UniTask.DelayFrame(120,cancellationToken: Token);
    }
}

Statusは内部挙動を把握してない使用すると危険みたいなので、上記の方法を使用せずにWhenAnyを使用すれば似たようなことができるのでそちらを利用した方がよさそうです

using System.Collections.Generic;
using UnityEngine;
using Cysharp.Threading.Tasks;
using System.Threading;
public class Test : MonoBehaviour
{
    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    void Start()
    {
        Application.targetFrameRate = 60;
    }

    async UniTaskVoid Update()
    {
        if (Input.GetKeyDown(KeyCode.F))
        {
            var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, this.GetCancellationTokenOnDestroy());
            await UniTask.WhenAny(TestFnuc(linkedTokenSource.Token), Print(linkedTokenSource.Token));
            cancellationTokenSource.Cancel();//WhenAnyは片方が終了しても、もう片方はTaskが走り続けるのでキャンセルさせる
            await UniTask.Yield();//Printがキャンセルされるまで1fかかるので待機
            Debug.Log("TestFnuc終了");
        }

    }
    async UniTask Print(CancellationToken Token)
    {
        Token.ThrowIfCancellationRequested();
        int frame = 0;

        while (true)
        {
            Token.ThrowIfCancellationRequested();
            await UniTask.Yield(cancellationToken: this.GetCancellationTokenOnDestroy());
            Debug.Log("TestFnuc実行中 frame[" + frame.ToString() + "]");
            frame++;
        }
    }

    async UniTask TestFnuc(CancellationToken Token)
    {
        Token.ThrowIfCancellationRequested();
        Debug.Log("TestFnuc開始");
        await UniTask.DelayFrame(120,cancellationToken: Token);
    }
}