63
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【UniRx】UniRxとコルーチン

Last updated at Posted at 2015-06-02

この記事はちょっと古いのでこちらの新しい記事を参照ください
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を上手に利用して読みやすく扱いやすいコードを書きましょう。

63
57
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
63
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?