知識0からのUnityShader勉強

知識0からのUnityShader勉強

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

【UniRx】メッセージ同士の合成 #97

前回の成果

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

soramamenatan.hatenablog.com


今回やること

今回はメッセージ同士の合成についてまとめます。


前回のメッセージの結果と今回の結果を使用したい

Scan

Scanで、前回の結果と今回の結果を使用することができます。

前回のメッセージの値と今回の値を加算する

/// <summary>
/// 前回のメッセージの値と今回の値を加算する
/// </summary>
private void ExcuteScanList() {
    Observable
        .Range(1, 5)
        .Scan((a, b) => a + b)
        .Subscribe(x => {
            Debug.Log(string.Format("ScanList onNext : " + x));
        }, () => {
            Debug.Log(string.Format("ScanList onCompleted"));
        });
}

結果

Rangeで今回は1~5までの値を流しています。
それをScanを使用することにより加算しています。

f:id:soramamenatan:20210409085614p:plain


何かキーが押されるたびにカウントされる

/// <summary>
/// 何かキーが押されるたびにカウントされる
/// </summary>
private void ExcuteScanOnAnyKeyDown()
{
    Observable
        .EveryUpdate()
        .Where(_ => Input.anyKeyDown)
        .Select(_ => 1)
        .Scan((a, b) => a + b)
        .Subscribe(x => {
            Debug.Log(string.Format("ScanOnAnyKeyDown onNext : " + x));
        }, () => {
            Debug.Log(string.Format("ScanOnAnyKeyDown onCompleted"));
        });
}

結果

何かキーが押される度にSelectが1を返してくれ、Scanを併せて使用することによりカウントを実装しています。
これにより、変数を用意しなくてもカウントを実装できます。

f:id:soramamenatan:20210409085811p:plain


メッセージを指定した数、まとめたい

Buffer

Bufferは指定した数メッセージをまとめる機能と、指定した数メッセージをスキップする機能があります。
定義は以下のようになっており、Countはまとめる数、Skipは飛ばす数となっております。
Skipを指定しない場合、Countと同じ数飛ばします

/// <summary>
/// メッセージをまとめる
/// </summary>
/// <param name="source">ストリーム</param>
/// <param name="count">まとめるメッセージ数</param>
/// <param name="skip">飛ばすメッセージ数</param>
public static IObservable<IList<T>> Buffer<T>(this IObservable<T> source, int count, int skip)

メッセージを複数にまとめる、引数1つ

/// <summary>
/// メッセージを複数にまとめる
/// 引数1つ
/// </summary>
private void ExcuteBufferSingle()
{
    Observable
        .Range(1, 5)
        .Select(x => x.ToString())
        // Buffer(2, 2)と同じ
        .Buffer(2)
        .Subscribe(x => {
            Debug.Log("Buffer : " + x.Aggregate<string>((sum, n) => sum.ToString() + ", " + n.ToString()));
        }, () => {
            Debug.Log(string.Format("Buffer onCompleted"));
        });
}

結果

Rangeで1~5の値が渡され、それが2つずつまとめられて、2つスキップされています。
最後の5は2つまとめることが出来ないので、そのまま流しています。

f:id:soramamenatan:20210409090443p:plain


メッセージを複数にまとめる、引数2つ

/// <summary>
/// メッセージを複数にまとめる
/// 引数2つ
/// </summary>
private void ExcuteBufferDouble()
{
    Observable
        .Range(1, 5)
        .Select(x => x.ToString())
        .Buffer(3, 2)
        .Subscribe(x => {
            Debug.Log("Buffer : " + x.Aggregate<string>((sum, n) => sum.ToString() + ", " + n.ToString()));
        }, () => {
            Debug.Log(string.Format("Buffer onCompleted"));
        });
}

結果

Bufferの第2引数を指定することでスキップする数を変更することができます。
今回は2を指定したので、2つずつスキップされます。
最後の5は3つまとめることが出来ないので、そのまま流しています。
f:id:soramamenatan:20210409091146p:plain


指定したObservableにメッセージが発行されるまでメッセージをまとめる

Buffer

Bufferの引数にObservableを指定することもできます。
そうした場合、指定したObservableにメッセージが来るまでメッセージをまとめることができます。

ダブルクリック検知

/// <summary>
/// 指定したObservableにメッセージが発行されるまでメッセージをまとめる
/// ダブルクリック検知
/// </summary>
private void ExcuteBufferDoubleClick()
{
    // クリック検知
    IObservable<Unit> clickObservable = this.UpdateAsObservable()
                                            .Where(_ => Input.GetMouseButtonDown(0));
    clickObservable
        // 200ms内のクリックをまとめる
        .Buffer(clickObservable.Throttle(TimeSpan.FromMilliseconds(200)))
        .Where(x=> x.Count == 2)
        .Subscribe(x => {
            Debug.Log("Buffer : Double Click");
        }, () => {
            Debug.Log(string.Format("Buffer onCompleted"));
        });
}

結果

Throttleは指定した時間経過後にonNextを発行するオペレータです。
Whereを使用して、2回カウントが来たらというフィルターをかけてあげます。
この2つとBufferを組み合わせることにより、ダブルクリックを検知することができます。
今回の場合、200ms以内に2回クリックをするとメッセージが発行されます。

f:id:soramamenatan:20210409091819p:plain


直線のメッセージと今回のメッセージの2つをセットにしたい

PairWise

PairWiseを使用することで、前回のメッセージと今回のメッセージを1つにまとめることができます。
Buffer(2, 1)と挙動が似ていますが、こちらは必ず2つで1セットになることが違いになります。

2つのメッセージを1つにまとめる
/// <summary>
/// 2つのメッセージを1つにまとめる
/// Buffer(2, 1)との違いは必ず2つでセットになること
/// </summary>
private void ExcutePairwise()
{
    Observable
        .Range(1, 5)
        // 2つのメッセージを1つにまとめる
        .Pairwise()
        .Subscribe(x => {
            Debug.Log(string.Format("Pairwise : {0}, {1}", x.Previous, x.Current));
        }, () => {
            Debug.Log(string.Format("Pairwise : onCompleted"));
        });

    // 比較用
    Observable
        .Range(1, 5)
        .Select(x => x.ToString())
        .Buffer(2, 1)
        .Subscribe(x => {
            Debug.Log("Buffer    : " + x.Aggregate<string>((sum, n) => sum.ToString() + ", " + n.ToString()));
        }, () => {
            Debug.Log(string.Format("Buffer    : onCompleted"));
        });

}
結果

Buffer(2, 1)と実際に比較してみると、最後のメッセージが異なります。
Pairwiseは必ず2つをまとめたメッセージが流れてきていますが、Bufferは1つでも関係なく流れています。

f:id:soramamenatan:20210410122849p:plain


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


参考サイト様

qiita.com