本日はアプリ作成枠です。
HoloLens2でホロモンアプリを作る進捗を書き留めていきます。
今回はホロモンアプリに感情マークの表示機能を追加するメモです。
感情マークの表示機能
ホロモンの頭部位置の追従オブジェクトに感情を表すアイコンを追加しました。
以下の2つのスクリプトで表示するマークと表示アニメーションを管理します。
・EmotionMarkSwitch.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace HMProject.EmotionUI { public class EmotionMarkSwitch : MonoBehaviour { [SerializeField, Tooltip("マークオブジェクトリスト")] private List<GameObject> p_MarkList; private enum MarkNumber { Exclamation = 0, Question = 1, } // Start is called before the first frame update void Start() { // 初期状態では全てのオブジェクトを無効化する foreach(GameObject mark in p_MarkList) { mark.SetActive(false); } } public bool ExclamationActive() { int activeNumber = (int)MarkNumber.Exclamation; // 指定のマークが登録されていない場合、処理しない if (p_MarkList.Count <= activeNumber) return false; // 全てのオブジェクトを無効化する foreach (GameObject mark in p_MarkList) { mark.SetActive(false); } // 指定のマークを有効化する p_MarkList[activeNumber].SetActive(true); return true; } public bool QuestionActive() { int activeNumber = (int)MarkNumber.Question; // 指定のマークが登録されていない場合、処理しない if (p_MarkList.Count <= activeNumber) return false; // 全てのオブジェクトを無効化する foreach (GameObject mark in p_MarkList) { mark.SetActive(false); } // 指定のマークを有効化する p_MarkList[activeNumber].SetActive(true); return true; } } }
・EmotionMarkAnimation.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; namespace HMProject.EmotionUI { public class EmotionMarkAnimation : MonoBehaviour { /// <summary> /// アニメーション完了時イベント /// </summary> public Action AnimationEndEvent; // Animatorの参照 private Animator p_Animator; // アニメーションパラメータのステータス名定義 private string p_ParameterStatusName = "MarkStatus"; // アニメーション実行中フラグ private bool p_AnimationFlg; // アニメーション状態定義 private enum EnumMarkStatus { Neutral = 0, Show = 1, } /// <summary> /// デフォルト状態のハッシュ値を取得 /// </summary> static int defaultState = Animator.StringToHash("Base Layer.NeutralState"); // Start is called before the first frame update void Start() { // 変数を初期化する p_AnimationFlg = false; p_Animator = this.GetComponent<Animator>(); } void Update() { if (!p_AnimationFlg) return; // アニメーション実行中は終了タイミングの検知を行う // アニメーションの再生完了(normalizedTime 1以上)をチェックする if (p_Animator.GetCurrentAnimatorStateInfo(0).fullPathHash != defaultState && p_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime > 1.0f) { // アニメーションの完了時イベントを呼び出す p_AnimationFlg = false; AnimationEndEvent?.Invoke(); } } /// <summary> /// 状態の初期化 /// </summary> public void NeutralAnimation() { p_Animator.SetInteger(p_ParameterStatusName, (int)EnumMarkStatus.Neutral); p_AnimationFlg = false; } /// <summary> /// マーク表示アニメーション /// </summary> public bool ShowAnimation() { // アニメーション実行中は処理しない if (p_AnimationFlg) return false; p_Animator.SetInteger(p_ParameterStatusName, (int)EnumMarkStatus.Show); p_AnimationFlg = true; return true; } } }
表示アニメーションはアニメーションコントローラで制御します。
ローカルの位置と回転で表示アニメーションを行うため、Animator コンポーネントの[Apply Root Motion]を有効にしています。
最後にこれらを合わせて管理するコントローラとなるスクリプトを作成します。
デバッグが行いやすいよう Inspector 上から関数実行を行うエディター拡張を追加しました。
・EmotionUIController.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; namespace HMProject.EmotionUI { public class EmotionUIController : MonoBehaviour { /// <summary> /// 完了時イベント /// </summary> public Action CompletedEvent; [SerializeField, Tooltip("マークアニメーションの参照")] private EmotionMarkAnimation p_EmotionMarkAnimation; [SerializeField, Tooltip("マーク切り替えの参照")] private EmotionMarkSwitch p_EmotionMarkSwitch; // 実行アニメーション定義 [Serializable] private enum EnumAnimation { Exclamation, Question, } [SerializeField, Tooltip("アクション実行中フラグ")] private bool p_ActionFlg; [SerializeField, Tooltip("終了検知フラグ")] private bool p_CompleteFlg; [SerializeField, Tooltip("実行アニメーション設定")] private EnumAnimation p_Animation; // Start is called before the first frame update void Start() { // イベント設定を行う p_EmotionMarkAnimation.AnimationEndEvent += CompleteAction; } // Update is called once per frame void Update() { if (p_ActionFlg == true && p_CompleteFlg == true) { // アクション完了時のイベント呼び出し CompletedEvent?.Invoke(); p_ActionFlg = false; p_CompleteFlg = false; } } public void ExclamationStart() { // モーション実行中は処理しない if (p_ActionFlg) return; // マークの切り替え p_EmotionMarkSwitch.ExclamationActive(); // マーク表示アニメーションの開始 p_EmotionMarkAnimation.ShowAnimation(); // 各種フラグの設定 p_ActionFlg = true; p_CompleteFlg = false; } public void QuestionStart() { // モーション実行中は処理しない if (p_ActionFlg) return; // マークの切り替え p_EmotionMarkSwitch.QuestionActive(); // マーク表示アニメーションの開始 p_EmotionMarkAnimation.ShowAnimation(); // 各種フラグの設定 p_ActionFlg = true; p_CompleteFlg = false; } private void CompleteAction() { // 状態を初期状態に戻す p_EmotionMarkAnimation.NeutralAnimation(); // 実行完了フラグを立てる // イベント呼び出しはUpdateメインスレッドで行う p_CompleteFlg = true; } } }
・EmotionUIControllerEditor.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using UnityEditor; namespace HMProject.EmotionUI { // 拡張するクラスを指定する [CustomEditor(typeof(EmotionUIController))] public class EmotionUIControllerEditor : Editor { // GUIの表示関数をオーバーライドする public override void OnInspectorGUI() { // 元のインスペクター部分を表示 base.OnInspectorGUI(); // targetを変換して対象スクリプトの参照を取得する EmotionUIController targetScript = target as EmotionUIController; // public関数を実行するボタンの作成 if (GUILayout.Button("ExclamationStartの実行")) { targetScript.ExclamationStart(); } // public関数を実行するボタンの作成 if (GUILayout.Button("QuestionStartの実行")) { targetScript.QuestionStart(); } } } } #endif
動作確認
シーンを再生して動作確認を行います。
ExclamationStart 関数を実行するとビックリマークが、QuestionStart 関数を実行するとハテナマークがアニメーションとともに表示されます。