Help us understand the problem. What is going on with this article?

【UniRx】UniRxとコルーチン

More than 1 year has passed since last update.

この記事はちょっと古いのでこちらの新しい記事を参照ください
UniRx入門 その5 -コルーチンとの併用-


UniRxはコルーチンと組み合わせることでより便利になります。
今回はその方法を紹介します。

コルーチンをObservableに変換する

Observable.FromCoroutineを使うことでコルーチンをObservableに変換することができます。
FromCoroutineについては@neueccさん本人が詳しく説明されていますので、こちらを参考にされるのが一番良いかと思います。

Unityのコルーチンの分解、或いはUniRxのMainThreadDispatcherについて

FromCoroutineは特にコルーチンから戻り値のあるObservableを作る方法の汎用性が高く、ファクトリーメソッドやオペレータを組み合わせるよりもより簡潔に処理を記述できる場合があります。

例)一定条件の時のみカウントダウンするタイマをコルーチンから作る

戻り値のあるObservableをコルーチンから作る
private void Start()
{
    //
    //playerの初期化とかここでやってる
    //

    //プレイヤが生存している時間を30秒間カウントダウンする
    //タイマの現在のカウント[秒]が通知される
    Observable.FromCoroutine<int>(observer => CountDownCoroutine(observer, 30, player))
        .Subscribe(count => Debug.Log(count));
}

/// <summary>
/// プレイヤが生きている間だけカウントダウンするタイマー
/// プレイヤが死んでいる場合はカウントは停止する
/// </summary>
IEnumerator CountDownCoroutine(IObserver<int> observer,int startTime,Player player)
{
    var currentTime = startTime;
    while (currentTime > 0)
    {
        if (player.IsAlive)
        {
            observer.OnNext(currentTime--);
        }
        yield return new WaitForSeconds(1);
    }
    observer.OnCompleted();
}

Observableをコルーチンに変換する

Observableをコルーチンに変換する場合はStartAsCoroutineを使います。

StartAsCoroutineの例
private void Start()
{
    StartCoroutine(CoroutineA());
}

IEnumerator CoroutineA()
{

    //コルーチンの実行結果を保存する変数
    var result = 0;

    //Observable.Rangeをコルーチンに変換する
    yield return Observable.Range(0, 10).StartAsCoroutine(c => result = c);

    Debug.Log("Result:"+result);
}
実行結果
Result:9

StartAsCoroutineは以下の特徴があります。

  • OnCompletedが発行されるまでの間yield return nullを繰り返し続ける
  • StartAsCoroutineの引数に渡した関数はOnCompleted発行時に1回だけ実行され最後のOnNext値が渡される

StartAsCoroutineの使いドコロ

StartAsCoroutineを上手く使うと、非同期処理が入り組んだ処理を同期処理っぽく扱えるようになります。
いわゆるTaskのawait処理っぽいものを実現することができるようになります。


private IEnumerator HeavyTaskCoroutine()
{
    //実行結果
    bool result = false;

    //非同期処理の待ち受け
    //Observable.Startは別スレッドで処理を実行する
    yield return Observable.Start(()=>HeavyTask()).StartAsCoroutine(x => result = x);

    //実行結果を判定する
    if (result)
    {
        Debug.Log("Success");
    }
    else
    {
        Debug.Log("Failure");
    }
}

/// <summary>
/// 実行に時間がかかる重い処理
/// </summary>
/// <returns>成否</returns>
bool HeavyTask()
{
    //重い処理をする
    Thread.Sleep(3000);

    //実行の成否を返す(擬似的にランダムにtrue/falseを返す)
    var random = new System.Random();
    return random.Next() % 2 == 0;
}

まとめ

UniRxはコルーチンと組み合わせることでより真価を発揮します。
全てをRxのストリームで無理に書くのではなく、FromCoroutineとStartAsCoroutineを上手に利用して読みやすく扱いやすいコードを書きましょう。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away