【UniRx】ObserveEveryValueChangedでフレーム間での値の変動を監視する

  • 26
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

UniRxについての記事のまとめはこちら


先日投稿した「未来のプログラミング技術をUnityで -UniRx-」において、値の変動を監視をUniRxで行う方法を紹介しました。
ですが、UniRxの3/22の更新分で「ObserveEveryValueChanged」という機能が修正され、値の変動の監視がとても簡単にできるようになったので使い方を紹介したいと思います。

ObserveEveryValueChanged()

ObserveEveryValueChangedは全クラスに対する拡張メソッドとして定義されており、以下の様な特徴があります。

  • 任意のクラスオブジェクトに対して使用できる(ただしUnityEngine.Object以外に適用するのは安全ではない
  • 対象のインスタンスオブジェクトのプロパティ値(プロパティに限らずに値を返すものなら何でも)が前フレームと比較して変化していた際にその値をOnNextに流す
  • 1フレーム内で発生した複数回の変動は検知できず、前フレームと今フレームの変化のみ検知できる
  • メッセージが流れるタイミングは厳密にはUpdate()ではなくコルーチンの実行タイミングとなる(参考)
  • 対象がUnityEngine.Objectの派生オブジェクトだった場合、Destroy時にOnCompletedが飛ぶ
  • MonoBehaviour以外の場所でも使用することができる

使用例)CharacterController.isGroundedを監視する

ObserveEveryValueChangedを使った例

//キャラクタが着地した瞬間の検知
characterController
    .ObserveEveryValueChanged(x => x.isGrounded)
    .Where(x => x)
    .Subscribe(_ => Debug.Log("OnGrounded!"));
比較)ObserveEveryValueChangedを使わない例(ObservableMonoBehaviourを継承している場合)
UpdateAsObservable()
    .Select(_ => characterController.isGrounded)
    .DistinctUntilChanged()
    .Where(x => x)
    .Subscribe(_ => Debug.Log("OnGrounded!"));

UpdateAsObservable().Select(_ => characterController.isGrounded).DistinctUntilChanged() の部分がなくなり、スッキリ書くことができました。

まとめ

ObserveEveryValueChanged()を使うことで「毎フレーム値の変動を監視して何かしたい」といったことがより簡潔に記述できるようになりました。
ただし、UnityEngine.Object以外のclassオブジェクトに対してObserveEveryValueChangedを使用すると手動でオブジェクト破棄時にSubscribeのDisposeを行う必要が出てくるので注意が必要です。
(追記:3/23に修正されてPOCOなインスタンスオブジェクトについても破棄時に勝手にOnCompletedが飛ぶようになったようです!)