知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UniRx】Observable自体を変換するオペレータ #96

前回の成果

Obsevableを合成するオペレータについて学んだ。

soramamenatan.hatenablog.com


今回やること

今回はObservable自体の変換をまとめます。


ObservableをReadOnlyReactivePropertyに変換

ToReadOnlyReactiveProperty

ReadOnlyReactivePropertyとは、名前のままReactivePropertyの読み取り専用のものになります。
ReactivePropertyとは、値を渡した際に、同じ値の場合何もしない、違う値の場合OnNextを発行してくれるものとなります。
詳しくは以下で解説しています。

soramamenatan.hatenablog.com

ToReactivePropertyとToReadOnlyReactivePropertyがあります。
こちらはどちらも戻り値に、ReadOnlyReactiveProperty<T>を返しているので、中身的には同じものとなります。

ToReactivePropertyの定義
public static IReadOnlyReactiveProperty<T> ToReactiveProperty<T>(this IObservable<T> source)
{
    return new ReadOnlyReactiveProperty<T>(source);
}
ToReadOnlyReactivePropertyの定義
public static ReadOnlyReactiveProperty<T> ToReadOnlyReactiveProperty<T>(this IObservable<T> source)
{
    return new ReadOnlyReactiveProperty<T>(source);
}


1秒に1回、現在時刻を通知する

Intervalを使用することにより、指定した間隔でメッセージを発行することができます。
その発行をDateTime.Nowにすることにより1秒に1回、現在時刻を通知することができます。

サンプルコード
/// <summary>
/// 1秒に1回、現在時刻を通知する
/// </summary>
private void ToReadOnlyReactivePropertyTimer() {
    ReadOnlyReactiveProperty<string> timer = Observable
                                                .Interval(TimeSpan.FromSeconds(1))
                                                .Select(_ => DateTime.Now.ToString())
                                                .ToReadOnlyReactiveProperty();
    timer
        .Subscribe(x => {
            Debug.Log("Now Time : " + x);
        }, () => {
            Debug.Log("Timer onCompleted");
        }).AddTo(this);
}
結果

f:id:soramamenatan:20210321153250p:plain


Selectで別のReactivePropertyに変換

Selectを使用することにより、今回はint型のReactivePropertyをbool型に変換することができます。
こうすることにより、HPの比較といったこともできるようになります。

サンプルコード
/// <summary>
/// Selectで別のReactivePropertyに変換
/// </summary>
private void ToReadOnlyReactivePropertySelect() {
    const int ENERGY_HP = 50;
    ReactiveProperty<int> hp = new ReactiveProperty<int>(1);
    // SelectでintをboolのReactivePropertyへ変換
    // HPが50を超えていたら元気
    ReadOnlyReactiveProperty<bool> isEnergy = hp.Select(x => x >= ENERGY_HP)
                                                .ToReadOnlyReactiveProperty();

    // isEnergy = false
    Debug.Log(string.Format("hp : {0}, isEnergy : {1}", hp, isEnergy));
    hp.Value = ENERGY_HP;
    // isEnergy = true
    Debug.Log(string.Format("hp : {0}, isEnergy : {1}", hp, isEnergy));
}
結果

f:id:soramamenatan:20210321153416p:plain


CombineLatestで2つのReactivePropertyを比較

CombineLatestは、合成元のObservableに値が流れたら、他のObservableの最後に発行した値を流すオペレータです。
今回の場合ですと、value1かvalue2の値が変化する度に値が比較されます。

/// <summary>
/// CombineLatestで2つのReactivePropertyを比較
/// </summary>
private void ToReadOnlyReactivePropertyCombineLatest() {
    ReactiveProperty<int> value1 = new ReactiveProperty<int>(0);
    ReactiveProperty<int> value2 = new ReactiveProperty<int>(1);
    // value1とvalue2を比較して同じ値だったらtrue
    ReadOnlyReactiveProperty<bool> isSameValue = Observable
                                                    .CombineLatest(value1, value2, (x, y) => x == y)
                                                    .ToReadOnlyReactiveProperty();
    Debug.Log(string.Format("value1 : {0}, value2 : {1}, isSameValue : {2}", value1, value2, isSameValue));
    value1.Value = 5;
    Debug.Log(string.Format("value1 : {0}, value2 : {1}, isSameValue : {2}", value1, value2, isSameValue));
    value2.Value = 5;
    Debug.Log(string.Format("value1 : {0}, value2 : {1}, isSameValue : {2}", value1, value2, isSameValue));
}
結果

f:id:soramamenatan:20210321154033p:plain


Observableをコルーチンに変換

ToYieldInstruction
/// <summary>
/// タイマーコルーチンの実行
/// </summary>
private void ExcuteTimerCoroutine() {
    Observable
        .FromCoroutine(TimerCoroutine)
        .Subscribe(x => {
            Debug.Log("OnNext");
        }, () => {
            Debug.Log("OnCompleted");
        });
}

/// <summary>
/// タイマーコルーチン
/// </summary>
/// <returns></returns>
private IEnumerator TimerCoroutine() {
    Debug.Log("1秒後に終了します");
    yield return Observable
                        .Timer(TimeSpan.FromSeconds(1))
                        .ToYieldInstruction();
}
結果

f:id:soramamenatan:20210321154743p:plain

また、SelectManyやWhenAllといったオペレータを使用することにより複数のObservableから変換したコルーチンを扱うこともできます。
詳しくは、以下で紹介しています。

soramamenatan.hatenablog.com

今回は以上となります。
ここまでご視聴ありがとうございました。


参考サイト様

nobollel-tech.hatenablog.com

neue.cc