本日はアプリ作成枠です。
HoloLens2でホロモンアプリを作る進捗を書き留めていきます。
今回はモードの基本動作を継承クラスで共通化します。
モードの共通設定
待機、食事、睡眠、対象追跡など様々なホロモンの動作モードを作成してきました。
これらのモードで共通する以下の要素を基底クラスとして定義しました。
- モードの開始/停止
- モードの状態と参照
・HoloMonModeLogicBase.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UniRx; using System; using HMProject.HoloMon; namespace HMProject.HoloMonLogic { public class HoloMonModeLogicBase : MonoBehaviour { /// <summary> /// モードロジック状態 /// </summary> [SerializeField, Tooltip("モードロジック状態")] protected HoloMonModeStatusReactiveProperty p_ModeLogicStatus = new HoloMonModeStatusReactiveProperty(HoloMonModeStatus.Nothing); // EveryValueChanged を使ってフレーム間で変化があった時のみ通知する /// <summary> /// モードロジック状態の EveryValueChanged オブザーバ保持変数 /// </summary> protected IObservable<HoloMonModeStatus> p_IObservableModeLogicStatusEveryValueChanged; /// <summary> /// モードロジック状態の EveryValueChanged オブザーバ参照変数 /// </summary> public IObservable<HoloMonModeStatus> IObservableModeLogicStatusEveryValueChanged => p_IObservableModeLogicStatusEveryValueChanged ?? (p_IObservableModeLogicStatusEveryValueChanged = p_ModeLogicStatus.ObserveEveryValueChanged(x => x.Value)); /// <summary> /// モードロジックの状態を取得する /// </summary> /// <returns></returns> public HoloMonModeStatus ModeStatus => p_ModeLogicStatus.Value; /// <summary> /// アニメーション操作の参照 /// </summary> protected HoloMonAnimationSingleton p_Animation => HoloMonAnimationSingleton.Instance; /// <summary> /// 共通コンポーネントの参照 /// </summary> protected HoloMonComponentsSingleton p_Component => HoloMonComponentsSingleton.Instance; /// <summary> /// モードを有効化する /// </summary> /// <returns></returns> public bool EnableMode() { bool result = false; result = EnableSetting(); return result; } /// <summary> /// モードを無効化する /// </summary> /// <returns></returns> public bool DisableMode() { bool result = false; result = DisableSetting(HoloMonModeStatus.Stopping); return result; } /// <summary> /// モードの各種設定を有効化する /// </summary> protected virtual bool EnableSetting() { // 開始モード状態を設定する p_ModeLogicStatus.SetValueAndForceNotify(HoloMonModeStatus.Runtime); return true; } /// <summary> /// モードの各種設定を無効化する /// </summary> protected virtual bool DisableSetting(HoloMonModeStatus a_DisableStatus) { // 終了モード状態を設定する p_ModeLogicStatus.SetValueAndForceNotify(a_DisableStatus); return true; } } }
モードの細かな設定を行う EnableSetting, DisableSetting 関数は各モード毎に上書きしたいので virtual 修飾子を追加しています。
docs.microsoft.com
本クラスを継承する睡眠モードのクラスは以下のような記述になります。
・HoloMonModeLogicSleep.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using UniRx; using HMProject.HoloMon; namespace HMProject.HoloMonLogic { public class HoloMonModeLogicSleep : HoloMonModeLogicBase { /// <summary> /// モードの設定を有効化する /// </summary> protected override bool EnableSetting() { // アニメーションを睡眠モードにする p_Animation.StartSleepMode(); // 開始モード状態を設定する base.EnableSetting(); return true; } /// <summary> /// モードの設定を無効化する /// </summary> protected override bool DisableSetting(HoloMonModeStatus a_DisableStatus) { // アニメーションを待機モードにする p_Animation.ReturnStandbyMode(); // 終了モード状態を設定する base.DisableSetting(a_DisableStatus); return true; } } }
睡眠モードではアニメーションの変更のみ行うため、EnableSetting, DisableSetting 関数を override 修飾子で作成しています。
また共通の処理を通すため、base 変数を使って基底クラスの関数の呼び出しも行っています。
基底クラスが MonoBehaviour を継承しているので、毎フレーム監視が必要なモードでは Update 関数を利用します。
以下はターゲットの方を向くモードのクラスです。
・HoloMonModeLogicTargetTurn
using System.Collections; using System.Collections.Generic; using UnityEngine; using UniRx; using System; using HMProject.HoloMon; namespace HMProject.HoloMonLogic { public class HoloMonModeLogicTargetTurn : HoloMonModeLogicBase { /// <summary> /// 追跡オブジェクトのマップ位置 /// </summary> [SerializeField, Tooltip("追跡オブジェクトのマップ位置")] Transform p_TargetPoint; /// <summary> /// 前回記録回転角 /// </summary> Quaternion p_BeforeRotation; /// <summary> /// 停止確認カウンタ /// </summary> int StopCheckCount; int StopCheckThreshold = 5; /// <summary> /// 追跡対象を設定する /// </summary> /// <param name="a_Target"></param> /// <returns></returns> public bool SetTargetTransform(Transform a_Target) { bool result = false; p_TargetPoint = a_Target; result = true; return result; } /// <summary> /// 定期処理 /// </summary> void Update() { // モードが実行中かチェックする if (p_ModeLogicStatus.Value == HoloMonModeStatus.Runtime) { // 現在の回転角を取得する Quaternion currentRotation = p_Component.GetRigidbody().transform.rotation; // 前回との差分を取得する float diffAngle = Quaternion.Angle(p_BeforeRotation, currentRotation); // Update間隔の係数を取得する float secCoefficient = 1.0f / Time.deltaTime; // 1秒あたりの回転速度を取得する float secAngle = diffAngle * secCoefficient; // 回転速度をアニメーションに通知する p_Animation.SetModelRotate(secAngle); // 正面を向いているか否か bool isFront = p_Component.GetBillboard().IsFront(); // 回転中か否か if (isFront) { // 回転していないならカウントアップ StopCheckCount++; // 敷居値回数以上停止していれば停止と判定する if (StopCheckCount > StopCheckThreshold) { // 停止すれば目標を達成したと判定する Debug.Log("Turn Achievement"); // 移動していなければ追跡を停止する DisableSetting(HoloMonModeStatus.Achievement); } } else { // 移動していればカウント初期化 StopCheckCount = 0; } // 最終的な回転角を記録する p_BeforeRotation = p_Component.GetRigidbody().transform.rotation; } } /// <summary> /// 回転モードの設定を有効化する /// </summary> protected override bool EnableSetting() { // アニメーションを回転モードにする p_Animation.StartTurnMode(); // ターゲットを指定する p_Component.GetBillboard().TargetTransform = p_TargetPoint; // 回転開始時は方向回転を有効化する p_Component.GetBillboard().isActive = true; // 現在の回転角を記録する p_BeforeRotation = p_Component.GetRigidbody().transform.rotation; // 停止チェックカウントを初期化する StopCheckCount = 0; // 開始モード状態を設定する base.EnableSetting(); return true; } /// <summary> /// 回転モードの設定を無効化する /// </summary> protected override bool DisableSetting(HoloMonModeStatus a_DisableStatus) { // アニメーションを待機モードにする p_Animation.ReturnStandbyMode(); p_Animation.SetModelRotate(0.0f); // 回転終了時は方向回転を無効化する p_Component.GetBillboard().isActive = false; // 回転角を初期化する p_BeforeRotation = new Quaternion(); // 停止チェックカウントを初期化する StopCheckCount = 0; // 終了モード状態を設定する base.DisableSetting(a_DisableStatus); return true; } } }