MRが楽しい

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

HoloLens2でホロモンアプリを作る その56(ホロモンの頭を撫でるとホロモンが反応する)

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

今回はホロモンの頭を撫でるとホロモンが反応するメモです。

頭に触られたことを判定する

頭に触られたことを判定する方法には、今回は視界システムと同じロジックを用いました。
UniRx.TriggersのOnTriggerStayAsObservable()を用いて、コライダーのイベントをフレーム毎にまとめて処理することができます。

using UniRx;
using UniRx.Triggers;

// ...

/// <summary>
/// 起動処理
/// </summary>
void Start()
{
    // コライダーの OnTriggerStay イベントに対する処理を定義する
    this.OnTriggerStayAsObservable()                    // OnTriggerStayイベントを検出する
        .BatchFrame()                                   // フレーム毎に値をまとめる
        .ObserveOnMainThread()                          // メインスレッドで行う
        .Subscribe(colliderlist =>
        {
            foreach (Collider collider in colliderlist)
            {
                // 検出されたコライダーに対して処理を行う
                // ....
            }
        })
        .AddTo(this);

f:id:bluebirdofoz:20210902232410j:plain

今回は1フレーム毎に処理を行っていますが、UniRxのOperatorを活用することで様々な条件でコライダーを処理できます。
bluebirdofoz.hatenablog.com

更に頭部中心座標から一定距離の位置にオブジェクトが近づくと、オブジェクトが頭に触れたと判定して対象オブジェクトの情報を Dictionary 型で収集します。
bluebirdofoz.hatenablog.com

頭を撫でる手がパーの形かどうかは以下のハンドトラッキングによる判定を用います。
bluebirdofoz.hatenablog.com

以下が一定距離内のオブジェクトを検出する実装コードです。
・TactileBodyRegister.cs

モーションの作成

撫でられた時のアニメーションには以下の繰り返しモーションを利用しました。
bluebirdofoz.hatenablog.com

実装コード

待機アクションのロジックに頭を撫でられたときのアクションを追加しました。
体に触れられた割込みが発生した際、その情報をチェックします。
頭部をパーの形の手で触れられていた場合、モーションを再生しています。

        /// <summary>
        /// 頭に触れられたことに反応する
        /// </summary>
        /// <param name="a_TaouchObject"></param>
        private bool TouchHeadReaction(TactileObjectWrap a_TactileObjectWrap)
        {
            bool isProcessed = false;

            // 頭部に触れたオブジェクトが右手もしくは左手か
            if ((a_TactileObjectWrap.CurrentFeatures().ObjectUnderstandType == ObjectUnderstandType.FriendRightHand)
                || (a_TactileObjectWrap.CurrentFeatures().ObjectUnderstandType == ObjectUnderstandType.FriendLeftHand))
            {
                // 手の状態を取得する
                int HandStatusHash = a_TactileObjectWrap.CurrentFeatures().ObjectUnderstandDataInterface.StatusHash();

#if UNITY_EDITOR
                // Editor上では確認のため、ピストル状態でパーと判定する
                if( HandStatusHash == (int)ObjectStatusHand.Hand_Pistol) HandStatusHash = (int)ObjectStatusHand.Hand_Par;
#endif

                if (HandStatusHash == (int)ObjectStatusHand.Hand_Par)
                {
                    // パーの手で触れられていた場合は頭を撫でられたアクションを行う

                    /// 頭を撫でられたアクションを実行する
                    p_ModeLogicCommon.ReferenceAnimation.SetReactionPose(ReactionPose.StrokingHead);

                    // トリガーを設定済みの場合は一旦破棄する
                    p_TempActionTrigger?.Dispose();

                    // アニメーション完了後キャンセルのトリガーを実行する
                    p_TempActionTrigger = p_ModeLogicCommon.ReferenceAnimation.AnimationTrigger
                        .OnStateUpdateAsObservable()
                        .Where(onStateInfo => !onStateInfo.Animator.IsInTransition(onStateInfo.LayerIndex)) // アニメーションの移行が完了するのを待つ
                        .Where(onStateInfo => onStateInfo.StateInfo.normalizedTime > 0.95) // アニメーションの完了直前を検出する
                        .Take(1)
                        .Subscribe(_ =>
                        {
                            // 通常ポーズに戻す
                            p_ModeLogicCommon.ReferenceAnimation.SetReactionPose(ReactionPose.Nothing);
                        })
                        .AddTo(this);

                    isProcessed = true;
                }
            }

            return isProcessed;
        }

ObservableStateMachineTriggerを使ってUniRxでアニメーションの終了を検知しています。
bluebirdofoz.hatenablog.com

動作確認

シーンを再生して動作を確認します。
f:id:bluebirdofoz:20210902232438j:plain

手で頭を撫でてあげるとホロモンが両手を挙げて反応しました。
f:id:bluebirdofoz:20210902232544j:plain