MRが楽しい

MRやVRについて学習したことを書き残す

UniRxのFirstやTakeを使ってボタンの押下をawaitを使って待機する その2(待機をキャンセルする)

本日は UniRx の小ネタ枠です。
UniRxのFirstやTakeを使ってボタンの押下をawaitを使って待機する方法を記事にします。

前回記事

以下の前回記事の続きです。
bluebirdofoz.hatenablog.com

ToUniTask

ToUniTaskを利用すると様々な型をUniTask型に変換できます。
Firstの返り値のIObservableをUniTaskに変換して待機することでキャンセルトークンを使ったキャンセルを行うことができます。

サンプルスクリプト

前回のサンプルスクリプトを改修してボタンオブジェクトが無効化された場合は待機をキャンセルするように修正しました。
・ButtonFirstAwaitCancelTest.cs

using System.Threading;
using Cysharp.Threading.Tasks;
using UniRx;
using UnityEngine;
using UnityEngine.UI;

public class ButtonFirstAwaitCancelTest : MonoBehaviour
{
    /// <summary>
    /// 待機ボタン
    /// </summary>
    private Button Button => _button ? _button : (_button = GetComponent<Button>());
    private Button _button = default;

    /// <summary>
    /// ボタン用キャンセルトークン
    /// </summary>
    private CancellationTokenSource cancellationTokenSource = default;

    /// <summary>
    /// ボタン有効時の処理
    /// </summary>
    void OnEnable()
    {
        // ボタン待機を開始する
        WaitButton().Forget();
    }
    
    /// <summary>
    /// ボタン無効時の処理
    /// </summary>
    void OnDisable()
    {
        // オブジェクトが無効化された場合はボタンの待機をキャンセルする
        cancellationTokenSource?.Cancel();
    }
    
    private async UniTask WaitButton()
    {
        cancellationTokenSource?.Cancel();
        cancellationTokenSource = new CancellationTokenSource();
        
        Debug.Log("ボタンが押されるまで待機します");
        
        // ボタンが押下されたらFirstがOnCompletedを発行して待機を完了する
        var result = await Button.OnClickAsObservable().First()
            .ToUniTask(cancellationToken: cancellationTokenSource.Token) // UniTaskに変換してキャンセルトークンを設定する
            .SuppressCancellationThrow(); // キャンセル時の例外をIsCanceledプロパティで取得できるようにする

        if (result.IsCanceled)
        {
            Debug.Log("ボタンの待機がキャンセルされました");
        }
        else
        {
            Debug.Log("ボタンが押されました");
        }
    }
}

サンプルシーンのButtonオブジェクトにスクリプトを設定して準備完了です。

シーンを再生するとFirstによるボタン押下の待機が開始します。

ボタンを押下するとawaitが解除されてボタン押下ログが表示されます。

ボタンが無効化されるとawaitがキャンセルトークンで中断されてキャンセルログが表示されます。