MRが楽しい

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

HoloLens2でホロモンアプリを作る その5(ObjectManipulatorとNavMeshAgentを切り替える)

本日はアプリ作成枠です。
HoloLens2でホロモンアプリを作る進捗を書き留めていきます。
f:id:bluebirdofoz:20210212232410j:plain

ホロモンの動作モードに合わせてObjectManipulatorとNavMeshAgentを切り替えるメモです。

NavMeshAgentを使ってホロモンに現実空間を歩かせる

ホロモンプロジェクトに NavMesh を使って現実世界の経路探索を行う機能を追加しました。
3Dモデルを経路探索で移動させる手順は以下を参照ください。
bluebirdofoz.hatenablog.com
f:id:bluebirdofoz:20210212232432j:plain

ただしホロモンオブジェクトに NavMeshAgent を設定すると NavMesh の移動領域とアタリ判定が優先されてしまい、ObjectManipulator で掴めなくなる問題が発生しました。
f:id:bluebirdofoz:20210212232443j:plain

対応策として NavMesh を用いた追跡モード以外の時は NavMeshAgent を無効化しておく実装としました。
f:id:bluebirdofoz:20210212232453j:plain

以下のようにスクリプトによってターゲットを指定されたときのみ NavMeshAgent を有効化し、何らかの原因で停止した場合は NavMeshAgent を無効化して停止します。
・MoveNavMeshAgent

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

using HMProject.HoloMon;

namespace HMProject.MoveLogic
{
    public class MoveNavMeshAgent : MonoBehaviour
    {
        [SerializeField, Tooltip("ホロモンモードマネージャー")]
        HoloMonModeStatusManager p_HoloMonModeStatusManager;

        [SerializeField, Tooltip("追跡プレイヤー")]
        Transform p_PlayerTransform;

        [SerializeField, Tooltip("参照エージェント")]
        NavMeshAgent p_Agent;

        [SerializeField, Tooltip("参照慣性")]
        Rigidbody p_Rigidbody;


        /// <summary>
        /// 追跡位置
        /// </summary>
        Vector3 TrackingPosition;

        
        /// <summary>
        /// 停止確認カウンタ
        /// </summary>
        int StopCheckCount;

        int StopCheckThreshold = 5;

        void Start()
        {
        }

        void Update()
        {
            // モード判定
            switch(p_HoloMonModeStatusManager.GetHoloMonMode())
            {
                case HoloMonMode.PlayerTracking:
                    // プレイヤー追跡の場合は常に位置を更新する
                    TrackingPosition = p_PlayerTransform.position;
                    break;
                default:
                    break;
            }

            if(p_HoloMonModeStatusManager.IsTracking())
            {
                p_Agent.destination = TrackingPosition;
                
                // 移動中か否か
                if(p_Agent.velocity.magnitude == 0.0f)
                {
                    // 移動していないならカウントアップ
                    StopCheckCount++;

                    // 敷居値回数以上停止していれば停止と判定する
                    if (StopCheckCount > StopCheckThreshold)
                    {
                        // スタンバイモードに変更可能か確認する
                        bool isChanged = p_HoloMonModeStatusManager.ChangeStandby();
                        if (isChanged)
                        {
                            Debug.Log("Track End");

                            // 移動していなければ追跡を停止する
                            DisableTrackingStatus();
                        }
                    }
                }
                else
                {
                    // 移動していればカウント初期化
                    StopCheckCount = 0;
                }
            }
            
        }

        public void TrackingPlayer()
        {
            Debug.Log("TrackingPlayer");

            // プレイヤー追跡モードに変更可能か確認する
            bool isChanged = p_HoloMonModeStatusManager.ChangePlayerTracking();
            if (isChanged)
            {
                // 目的地を設定する
                TrackingPosition = p_PlayerTransform.position;

                EnableTrackingStatus();
            }
        }

        public void TrackingTarget(Transform a_transform)
        {
            Debug.Log("SetGoal");

            // ターゲット追跡モードに変更可能か確認する
            bool isChanged = p_HoloMonModeStatusManager.ChangeTargetTracking();

            if (isChanged)
            {
                // 目的地を設定する
                TrackingPosition = a_transform.position;

                EnableTrackingStatus();
            }
        }

        private void EnableTrackingStatus()
        {
            // 追跡中はエージェントを有効化する
            p_Agent.enabled = true;
            p_Rigidbody.useGravity = false;

            // 停止チェックカウントを初期化する
            StopCheckCount = 0;

        }

        private void DisableTrackingStatus()
        {
            // 追跡終了時はエージェントを無効化する
            p_Agent.enabled = false;
            p_Rigidbody.useGravity = true;
            p_Rigidbody.angularVelocity = Vector3.zero;

            // 停止チェックカウントを初期化する
            StopCheckCount = 0;

        }
    }
}

これで NavMesh による経路探索と、ObjectManipulator による自由移動が切り替えられるようになりました。
f:id:bluebirdofoz:20210212232505j:plain

注意点として切り替え時に不整合が発生するのを防ぐため、NavMeshAgent のアタリ判定とキャラクター自身のアタリ判定を凡そ同じサイズに設定しておく必要があります。
f:id:bluebirdofoz:20210212232515j:plain