MRが楽しい

MRやVRについて学習したことを書き残す

UniRxのReactivePropertyをReadOnlyで参照して購読を行う

本日は UniRx の小ネタ枠です。
UniRxのReactivePropertyをReadOnlyで参照して購読を行う方法を記事にします。
f:id:bluebirdofoz:20210218020800j:plain

前提条件

前回記事の続きです。
bluebirdofoz.hatenablog.com

前回記事では値が変更した場合に呼び出す関数を ReactiveProperty を持つクラスに渡して登録していました。
今回は読み取り専用の ReadOnlyReactiveProperty を参照して実行する処理を直接登録してみます。
f:id:bluebirdofoz:20210218020817j:plain

実装サンプル

前回のクラスを改修して以下の2つの方法で ReadOnlyReactiveProperty を参照してみます。
1.アップキャストでのIReadOnlyReactivePropertyの取得
2.ToReadOnlyReactiveProperty()でのReadOnlyReactivePropertyの取得

・HoloMonModeStatusSingleton.cs

using UnityEngine;
using UniRx;

namespace HMProject.HoloMon
{
    public class HoloMonModeStatusSingleton : MonoBehaviour
    {
        /// <summary>
        /// 単一インスタンス
        /// </summary>
        private static HoloMonModeStatusSingleton ps_instance;

        /// <summary>
        /// 参照用インスタンス
        /// </summary>
        public static HoloMonModeStatusSingleton Instance
        {
            get
            {
                if (ps_instance == null && ps_searchForInstance)
                {
                    ps_searchForInstance = false;
                    var ps_instances = FindObjectsOfType<HoloMonModeStatusSingleton>();
                    if (ps_instances.Length == 1)
                    {
                        ps_instance = ps_instances[0];
                    }
                    else if (ps_instances.Length > 1)
                    {
                        Debug.LogErrorFormat("Expected exactly 1 {0} but found {1}.", ps_instance.GetType().ToString(), ps_instances.Length);
                    }
                }
                return ps_instance;
            }
        }

        private static bool ps_searchForInstance = true;


        /// <summary>
        /// ホロモンモード
        /// </summary>
        [SerializeField, Tooltip("ホロモンモード")]
        private HoloMonModeReactiveProperty p_HoloMonMode
            = new HoloMonModeReactiveProperty(HoloMonMode.Standby);

        /// <summary>
        /// 1.アップキャストでのIReadOnlyReactivePropertyの取得
        /// </summary>
        public IReadOnlyReactiveProperty<HoloMonMode> IReadOnlyReactiveProperty => p_HoloMonMode;

        /// <summary>
        /// 2.ToReadOnlyReactiveProperty()でのReadOnlyReactivePropertyの取得
        /// </summary>
        public ReadOnlyReactiveProperty<HoloMonMode> GetReadOnlyReactiveProperty()
        {
            // ReadOnlyReactivePropertyの取得
            return p_HoloMonMode.ToReadOnlyReactiveProperty();
        }

        // ..略..

    }
}

f:id:bluebirdofoz:20210218020830j:plain

登録する側は以下のように ReadOnlyReactiveProperty に直接購読できます。
・TrackingMoveController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

using HMProject.HoloMon;

// Subscribeを行うため、UniRxを参照
using UniRx;

namespace HMProject.MoveLogic
{
    public class TrackingMoveController : MonoBehaviour
    {

        // ..略..

        /// <summary>
        /// 開始処理
        /// </summary>
        void Start()
        {
            // ..略..

            // ホロモンモード変化時のイベントを登録する

            // 1.アップキャストでのIReadOnlyReactivePropertyでの設定
            HoloMonModeStatusSingleton.Instance.IReadOnlyReactiveProperty
                .ObserveOnMainThread()
                .Subscribe(x => {
                    Debug.Log("From IReadOnlyReactiveProperty");
                    ChangeHoloMonMode(x);
                })
                .AddTo(this);

            // 2.ToReadOnlyReactiveProperty()でのReadOnlyReactivePropertyでの設定
            HoloMonModeStatusSingleton.Instance.GetReadOnlyReactiveProperty()
                .ObserveOnMainThread()
                .Subscribe(x => {
                    Debug.Log("From GetReadOnlyReactiveProperty()");
                    ChangeHoloMonMode(x);
                })
                .AddTo(this);
        }

        // ..略..

        /// <summary>
        /// ホロモンモード変更に合わせた切り替え
        /// </summary>
        /// <param name="a_HoloMonMode"></param>
        public void ChangeHoloMonMode(HoloMonMode a_HoloMonMode)
        {
            Debug.Log("TrackingMoveController ChangeHoloMonMode:" + a_HoloMonMode.ToString());
            switch (a_HoloMonMode)
            {
                case HoloMonMode.PlayerTracking:
                case HoloMonMode.TargetTracking:
                    EnableTrackingStatus();
                    break;
                default:
                    DisableTrackingStatus();
                    break;
            }
        }
    }
}

f:id:bluebirdofoz:20210218020842j:plain

実際にアプリケーションを起動して、モードの切り替えを発生させてみます。
ログを見るとモードが切り替わったときに、それぞれの処理が呼び出されていることが分かります。
f:id:bluebirdofoz:20210218020854j:plain

読み取り専用

ReadOnlyReactiveProperty の値は読み取り専用であるため、外部から Value の値を変更することはできません。
f:id:bluebirdofoz:20210218020903j:plain

これで ReactiveProperty の値へのアクセスを制御しつつ、外部から自由に購読や解除が行えるようになります。
前回記事の手順と比べた場合のデメリットは外部スクリプトが UniRx を参照する必要があるくらいなので、こちらのやり方を推奨します。