MRが楽しい

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

UniRxのContinueWithを使ってIObservableを一度だけ差し替える

本日はUniRxの小ネタ枠です。
UniRxのContinueWithを使ってIObservableを一度だけ差し替える方法を記事にします。

前提条件

UniRxの環境構築手順は以下の記事を参照ください。
bluebirdofoz.hatenablog.com

UniRxのContinueWithを使ってIObservableを一度だけ差し替える

UniRxのContinueWithはObservableから新しいIObservableを返します。
また、この差し替えが行われるのはOnCompletedが呼び出されたタイミングの一回のみという特徴があります。

以下にサンプルスクリプトを作成しました。
こちらはIObservableの差し替えがシーン再生5秒後に一度のみ実行されます。
・UniRxContinueWithTest.cs

using System;
using UniRx;
using UnityEngine;

public class UniRxContinueWithTest : MonoBehaviour
{
    private void Start()
    {
        // 5秒後に一度のみ通知が行われる
        Observable.Timer(TimeSpan.FromSeconds(5.0f))
            .Do(_ => Debug.Log($"通知が行われました"))
            // 一回だけObservableの差し替えが行われる
            .ContinueWith(_ =>
            {
                var timerSec = 3.0f;
                return Observable.Interval(TimeSpan.FromSeconds(timerSec)).Select(count => (count+1)*timerSec);
            })
            // 以降はIntervalの通知を基にログを出力する
            .Subscribe(elapsedTime => Debug.Log($"{elapsedTime}秒前に通知が行われました"));
    }
}


ContinueWithによるObservableの差し替えはOnCompletedが呼び出されたタイミングで実行されます。
このため、以下のようにTimerを完了しないコードに変更するとContinueWithによる差し替えは動作せず、Observable.Intervalの通知が発生しません。
・UniRxContinueWithTest.cs

using System;
using UniRx;
using UnityEngine;

public class UniRxContinueWithTest : MonoBehaviour
{
    private void Start()
    {
        // 5秒後から定期的に通知が行われる
        Observable.Timer(TimeSpan.FromSeconds(5.0f), TimeSpan.FromSeconds(5.0f))
            .Do(_ => Debug.Log($"通知が行われました"))
            // 本コードではObservableの差し替えが行われない
            .ContinueWith(_ =>
            {
                var timerSec = 3.0f;
                return Observable.Interval(TimeSpan.FromSeconds(timerSec)).Select(count => (count+1)*timerSec);
            })
            .Subscribe(elapsedTime => Debug.Log($"{elapsedTime}秒前に通知が行われました"));
    }
}