MRが楽しい

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

HoloLens2でホロモンアプリを作る その55(Dictionary型で保持する視認オブジェクトのキーにInstanceIDを利用する)

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

今回は Dictionary 型で保持する視認オブジェクトのキーに InstanceID を利用するメモです。

Object.GetInstanceID

オブジェクトの InstanceID を返します
オブジェクトの InstanceID は常にユニークです。
docs.unity3d.com

視認オブジェクトを保持する

以下の記事で書き留めた通り、ホロモンは自身の周囲のオブジェクトに対して視野判定を行い、視認オブジェクトを検出します。
bluebirdofoz.hatenablog.com

検出したオブジェクトは Dictionary 型で管理し、その関連を取るためのキー値として Object.GetInstanceID を利用しました。
・FieldOfVisionCollection.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEditor;
using System;

// ToList使用のため
using System.Linq;

namespace HoloMonApp.FieldOfVisionSpace
{
    /// <summary>
    /// 視界内の視界オブジェクトコレクション
    /// </summary>
    public class FieldOfVisionCollection : MonoBehaviour
    {
        /// <summary>
        /// 視界内の視認オブジェクトリスト
        /// </summary>
        private Dictionary<int, VisionObjectWrap> p_VisionObjectDictionary
            = new Dictionary<int, VisionObjectWrap>();

        [SerializeField, Tooltip("視界内の視認オブジェクトリスト(Editor確認用)")]
        private List<VisionObjectWrap> p_FieldOfVisionWrapList;

        /// <summary>
        /// 視界内の特徴ハッシュ値リスト
        /// </summary>
        private Dictionary<int, int> p_VisionObjectFeatureHashDictionary
            = new Dictionary<int, int>();

        [SerializeField, Tooltip("視界内の特徴ハッシュ値リスト(Editor確認用)")]
        private List<int> p_VisionObjectFeatureHashList;

        /// <summary>
        /// 発見イベント
        /// </summary>
        public Action<VisionObjectWrap> FindObjectWrapEvent;

        /// <summary>
        /// ロストイベント
        /// </summary>
        public Action<int> LostObjectNameEvent;

        /// <summary>
        /// 状態アップデートイベント
        /// </summary>
        public Action<VisionObjectWrap> UpdateStatusObjectWrapEvent;

        private void UpdateList()
        {
# if UNITY_EDITOR
            // Editor確認用
            if (EditorApplication.isPlaying)
            {
                p_FieldOfVisionWrapList = p_VisionObjectDictionary.Values.ToList();
                p_VisionObjectFeatureHashList = p_VisionObjectFeatureHashDictionary.Values.ToList();
            }
# endif
        }


        /// <summary>
        /// オブジェクト追加
        /// </summary>
        public void Add(VisionObjectWrap a_VisionObjectWrap)
        {
            p_VisionObjectDictionary.Add(a_VisionObjectWrap.Object.GetInstanceID(), a_VisionObjectWrap);
            p_VisionObjectFeatureHashDictionary.Add(a_VisionObjectWrap.Object.GetInstanceID(), a_VisionObjectWrap.CurrentStatusHash());
            UpdateList();
            FindObjectWrapEvent.Invoke(a_VisionObjectWrap);
        }

        /// <summary>
        /// オブジェクト削除
        /// </summary>
        public bool Remove(GameObject a_Object)
        {
            bool result = Remove(a_Object.GetInstanceID());

            return result;
        }

        /// <summary>
        /// 状態の更新チェック
        /// </summary>
        public bool CheckStatusUpdate()
        {
            bool isUpdated = false;

            foreach(int key in p_VisionObjectDictionary.Keys)
            {
                int currentStatusHash = p_VisionObjectDictionary[key].CurrentStatusHash();

                if (currentStatusHash != p_VisionObjectFeatureHashDictionary[key])
                {
                    p_VisionObjectFeatureHashDictionary[key] = currentStatusHash;
                    UpdateList();
                    UpdateStatusObjectWrapEvent.Invoke(p_VisionObjectDictionary[key]);
                    isUpdated = true;
                }
            }

            return isUpdated;
        }

        /// <summary>
        /// VisionObjectの取得
        /// </summary>
        public VisionObjectWrap GetVisionObject(GameObject a_Object)
        {
            return p_VisionObjectDictionary[a_Object.GetInstanceID()];
        }

        /// <summary>
        /// 値の存在チェック
        /// </summary>
        public bool ContainsKey(GameObject a_Object)
        {
            return p_VisionObjectDictionary.ContainsKey(a_Object.GetInstanceID());
        }

        /// <summary>
        /// キー一覧の取得
        /// </summary>
        public List<int> KeyList()
        {
            return p_VisionObjectDictionary.Keys.ToList();
        }

        /// <summary>
        /// 値一覧の取得
        /// </summary>
        public List<VisionObjectWrap> ValueList()
        {
            return p_VisionObjectDictionary.Values.ToList();
        }

        /// <summary>
        /// 指定リストに含まれないオブジェクトをコレクションから除去する
        /// </summary>
        public bool RemoveWithoutList(List<GameObject> a_CheckObjectList)
        {
            bool isRemoved = false;

            // オブジェクトInstanceIDのリストに全て変換する
            List<int> checkIdList = a_CheckObjectList.ConvertAll(obj => obj.GetInstanceID());

            foreach (int key in p_VisionObjectDictionary.Keys.ToList())
            {
                if (!checkIdList.Contains(key))
                {
                    // 検出されていなければコレクションから削除する
                    Remove(key);
                    isRemoved = true;
                }
            }

            return isRemoved;
        }

        /// <summary>
        /// オブジェクト削除(ID指定)
        /// </summary>
        private bool Remove(int a_InstanceID)
        {
            bool removed = p_VisionObjectDictionary.Remove(a_InstanceID);

            if (removed)
            {
                p_VisionObjectFeatureHashDictionary.Remove(a_InstanceID);
                UpdateList();
                LostObjectNameEvent.Invoke(a_InstanceID);
            }
            return removed;
        }
    }
}

f:id:bluebirdofoz:20210901223747j:plain

動作確認

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

ハンドオブジェクトやボールオブジェクトを視認すると、検出リストにオブジェクトが追加されます。
f:id:bluebirdofoz:20210901223810j:plain

視界から外れたオブジェクトは InstanceID チェックによる除去処理によって削除されます。
f:id:bluebirdofoz:20210901223821j:plain