Nobollel開発者ブログ

Nobollelのエンジニアが、UnityやCocos2d-xの旬な情報・技術を紹介します。

Select+Switchについて

こんにちは、Nobollelエンジニアの古屋です。 前回、UniRxのReactivePropertyについて記事を書きました。今回は、その中で出てきたSelect+Switchについてもう少し書こうと思います。

SelectMany

前回の記事では、Select+SwitchをSelectと対比させて書きましたが、Select+SwitchはSelectManyにも似ています。

SelectManyは、シーケンスから複数のシーケンスを分岐させるときに使います。たとえば、ボタンをクリックするとキャラクターが攻撃するような処理は、SelectManyを使って次のように書けます:

IObservable<Unit> Click() {
    // ボタンがクリックされる度にUnitを返す
}

IObservable<int> Attack() {
    // 攻撃を開始し、1秒後にダメージ量を返す
}

void Start() {
    Click().SelectMany(_ => Attack()).Subscribe(damage => {
        Debug.Log("damage=" + damage);
    });
}

このコードでは、単純にクリックされる度にキャラクターが攻撃するので、連続でクリックすると攻撃が何重にも走ります。シューティングのように弾を飛ばす攻撃ならこのままでも良いかもしれませんが、キャラクターが剣を振って攻撃するようなゲームでは、このままでは少し具合が悪いかもしれません。

Select+Switch

SelectManyをSelect+Switchに置き換えると、攻撃が重複しないようにできます。

void Start() {
    Click().Select(_ => Attack()).Switch().Subscribe(damage => {
        Debug.Log("damage=" + damage);
    });
}

上のコードでは、一度クリックしてAttackを開始し、Attackが完了する1秒以内にもう一度クリックすると、最初のAttackがキャンセルされ、2回目のAttackのダメージ量だけがログに表示されます。最も新しいAttackが優先され、同時に複数のAttackが重なって実行されることはなくなります。

このように、何かのイベントをトリガーに非同期処理を行い、かつ重複させたくないときにSelect+Switchを使うことができます。

ところで、さきほどのSelectManyのコードは、Select+Mergeでも同じことができます。こちらの方がSelect+Switchと形が似ていて、比較がわかりやすいかもしれません。

void Start() {
    Click().Select(_ => Attack()).Merge().Subscribe(damage => {
        Debug.Log("damage=" + damage);
    });
}