UniRxのシンプルなサンプル その1(Subscribe イベントの登録)


UniRxのシンプルなサンプルの取扱説明書
前(Rx オーバービュー)
次(WhereとSelect)

UniRxの簡単なサンプル

ずっとRxって気になってたんですけどいろんなサイトの説明難しかったので全然勉強できてなかったです。
というわけで簡単なSampleを元に勉強がてらまとめていきたいと思います。

ちなみに対象読者はIEnumeratorのLINQはわかってるしeventもわかるよくらいのC#er

UniRxで説明してるけどRxでも大丈夫な… はず!!
(といいつつサンプルに使うのはUniRxのみのEveryUpdateがメインだったりして)

そもそもRxって何?

誤解を恐れず超ざっくり言うなら
C#の人向け
*
多機能なevent

web系の人向け
*
多機能なjQuery

です。

だから例えばボタンがクリックされたら何かの処理をするとか
ボタンにマウスが乗ったら色が変わるとかもできます。

それだけじゃないのでちゃんとお勉強してみます。

もうちょっとまともな説明

Rxを構成するパーツは2つあります。

まず一つ目は処理の流れです。
ボタンのeventでいうところのこれ

events
//              ↓これ
button.Click += button_Click;

要はクリックされたら何したいとか何秒後に何したいとかそのイベントが起きたらしたいこと

これがObserverパターンのリスナーとか言うやつらしい

もう一つはこの処理の流れに値を入れて処理を起動するオブジェクト
要するにボタンが押されたらこれやってっていうイベントの登録先

これがObserverパターンのオブザーバーとか言うやつらしい

この2つを合わせて
1:オブザーバーに処理の流れを登録
2:対応したイベントが起こったら処理の流れに値を入れて処理させてあげる

図にするとこんなかんじ

と長々説明したけど、この考え方はC#にはもうあってていうか既に何度も言ってるけどイベントって言います。

大事なのはこのRxはイベントの延長として捉えられるということです。
何かが起きたらイベントがおきるというフローが素直に適用できます。

一方、イベントにはない便利な機能がたくさんあります。
なのでこれからRxならではの能力なんかを説明していけたらいいなーって思います。
(ただしUniRxでやる)

一番簡単なサンプル

まず、StartしたらGameObjectが(0,1)に移動するっていう処理をUniRxで書いてみます。
何事も簡単なやつからですよね。

というわけでただのSprite作ってそこにSubscribeとかいうスクリプト作って貼っつけただけのゲームオブジェクトを作成します。

Subscribe.csの中身はこんなかんじです

Subscribe.cs
using UnityEngine;
using System.Collections;
using UniRx;

public class SubscribeSample : MonoBehaviour
{
    // Use this for initialization
    void Start () {
        //Returnで(0,1)という値をSubscribe内に流し込んでる
        Observable.Return(new Vector2(0, 1))
            .Subscribe(v => gameObject.transform.position = v);
}

まず値を流し込む側の登録先は
Observable.Return(new Vector2(0, 1))
です。
Observable.Return(T value)はvalueを一回だけ登録された処理に流し込みます(この流し込みをプッシュといいます)。
つまり今回は登録された処理に一回だけnew Vector2(0, 1)を流し込んでいます。

次にSubscribeで登録しています。
今回は引数が位置情報であると期待してgameObjectのpositionをその位置にしているだけです。
登録先.Subscribe(Action onNext)で登録先にonNextという処理を登録するということになります。eventの+=に対応します。

このObservableというクラスは他にもいろいろな値の流し込み方が定義されているのでおいおい説明します。

これを実行するとスプライトが(0,1)の位置に来ると思います。

では次にその後アップデート後に右に動くようにしましょう。

lang
using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;

public class SubscribeSample : MonoBehaviour
{

    // Use this for initialization
    void Start () {

        //Returnで(0,1)という値をSubscribe内に流し込んでる
        Observable.Return(new Vector2(0, 1))
            .Subscribe(v => gameObject.transform.position = v);

        //UpdateAsObservableでUpdateのたびに値流しこんでる
        this.UpdateAsObservable().Subscribe(_ => Move(0.01f, 0));
//イベントだと this.update += _=>Move(0.01f, 0)という感じ(updateなんてイベントないけど)
    }


    /// <summary>
    /// (dx,dy)だけ移動させる
    /// </summary>
    /// <param name="dx"></param>
    /// <param name="dy"></param>
    public void Move(float dx, float dy)
    {
        gameObject.transform.position += new Vector3(dx, dy, 0);
    }
}

今度はthis.UpdateAsObservable()という登録先です。
これはアップデート時に毎回処理を起動してくれる登録先になります。
ちなみにこのthisは省略できません。これはUniRx.Triggers.ObservableTriggerExtensions;に定義されている拡張メソッドだからです。

ここでフレームごとに位置を更新しています。
つまりこれを実行したら(0,1)に移動した後右にずずずいっと動き続けます。

こんなかんじで登録先に登録してその登録先が適切なタイミングで値を処理に流しこんでくれるのがRxのスタートラインです。

とりあえず今回はここまで

ところでこのUniRxさん日本人neueccさんが作成してくれているのでJapaneseで作者のページ読めるの大変ありがたいです。

このサンプルではオブジェクトの寿命を考慮していません。詳しくはUniRxのシンプルなサンプル その6(購読の停止)を参照してください。