LoginSignup
12
10

More than 5 years have passed since last update.

コルーチンの中でボタンのクリックを待つ

Last updated at Posted at 2017-04-29

ボタンがひとつの場合

    [SerializeField]
    private Button _button1;

    void Start()
    {
        StartCoroutine(WaitButtonClick(_button1));
    }

    IEnumerator WaitButtonClick(Button button)
    {
        yield return button.OnClickAsObservable().First().ToYieldInstruction();
        Debug.LogFormat("{0} がクリックされました", button.name);
    }

ボタンがふたつの場合

どちらのボタンが押されたのかも取得できるようにします。

    [SerializeField]
    private Button _button1;

    [SerializeField]
    private Button _button2;

    void Start()
    {
        StartCoroutine(WaitButtonClick(_button1, _button2));
    }

    IEnumerator WaitButtonClick(Button button1, Button button2)
    {
        var s = Observable.Merge(button1.OnClickAsObservable().Select(_ => button1),
                                 button2.OnClickAsObservable().Select(_ => button2));
        var y = s.First().ToYieldInstruction();
        yield return y;
        Debug.LogFormat("{0} がクリックされました", y.Result.name);
    }

ボタンが 3 つ以上の場合

    [SerializeField]
    private Button _button1;

    [SerializeField]
    private Button _button2;

    [SerializeField]
    private Button _button3;

    void Start()
    {    
        StartCoroutine(WaitButtonClick(_button1, _button2, _button3));
    }

    IEnumerator WaitButtonClick(params Button[] buttons)
    {
        var y = buttons.Select(b => b.OnClickAsObservable().Select(_ => b))
            .Aggregate((a, b) => a.Merge(b))
            .First()
            .ToYieldInstruction();
        yield return y;                                                        
        Debug.LogFormat("{0} がクリックされました", y.Result.name);
    }

タイムアウトを設けてキャンセルできるようにする

Timeout メソッドを使うと、タイムアウトするまでの時間が設定できます。

IEnumerator WaitButtonClick(int timeoutSeconds, params Button[] buttons)
{
    var y = buttons.Select(b => b.OnClickAsObservable().Select(_ => b))
        .Aggregate((a, b) => a.Merge(b))
        .Timeout(TimeSpan.FromSeconds(timeoutSeconds)) // timeoutSeconds 秒でタイムアウト
        .First()
        .ToYieldInstruction(throwOnError: false);
    yield return y;

    if (y.HasError)
    {
        if (y.Error is TimeoutException)
        {
            Debug.LogFormat("タイムアウトしました");
        }
    }
    else
    {
        Debug.LogFormat("{0} がクリックされました", y.Result.name);
    }
}

ToYieldInstruction の引数に CancellationToken を渡して、外部からキャンセルできるようにする

class Canceller : ICancelable
{
    private bool _isDisposed;

    public bool IsDisposed { get { return _isDisposed; } }

    public void Dispose()
    {
        _isDisposed = true;
    }
}

private void Start()
{
    var canceller = new Canceller();
    // _button0 をクリックしたらキャンセル
    _button0.onClick.AddListener(() => canceller.Dispose());

    StartCoroutine(WaitButtonClick(new CancellationToken(canceller), _button1, _button2, _button3));
}

IEnumerator WaitButtonClick(CancellationToken cancel, params Button[] buttons)
{
    var y = buttons.Select(b => b.OnClickAsObservable().Select(_ => b))
        .Aggregate((a, b) => a.Merge(b))
        .First()
        .ToYieldInstruction(cancel);
    yield return y;

    if (y.IsCanceled)
    {
        Debug.LogFormat("キャンセルされました");
    }
    else
    {
        Debug.LogFormat("{0} がクリックされました", y.Result.name);
    }
}
12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10