MRが楽しい

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

HoloLens2でホロモンアプリを作る その112(行動ロジックを継承クラスにして共通部分を纏める)

本日はアプリ作成枠です。
HoloLens2でホロモンアプリを作る進捗を書き留めていきます。
行動ロジックを継承クラスにして共通部分を纏める修正を行いました。

Unityの共通処理を継承クラスに纏める

ホロモンアプリにはホロモンの行動ロジックを処理するクラスを行動毎に作成しています。
以下の記事で試した手法を基に、共通処理と Unity のライフサイクルに関する部分をベースクラスに纏めました。
bluebirdofoz.hatenablog.com


以下、ベースクラスと行動クラスの一例です。
・PurposeLogicBase.cs(ベースクラス)

using Cysharp.Threading.Tasks;
using UnityEngine;

using HoloMonApp.Content.Character.Behave.ModeLogic;
using HoloMonApp.Content.Character.Control;
using HoloMonApp.Content.Character.View;

namespace HoloMonApp.Content.Character.Behave.Purpose
{
    public abstract class PurposeLogicBase : MonoBehaviour, HoloMonPurposeBehaveIF
    {
        // 参照用変数
        protected HoloMonControlAPI p_Control => p_BehaveReference.Control;
        protected HoloMonViewAPI p_View => p_BehaveReference.View;
        protected HoloMonActionModeLogicAPI p_ActionModeLogic => p_PurposeBehaveReference.ActionModeLogic;
        protected PurposeDataInterface p_DataInterface => p_Info.PurposeData;

        /// <summary>
        /// 共通参照
        /// </summary>
        [Header("Initialize")]
        [SerializeField]
        private HoloMonBehaveReference p_BehaveReference;
        
        /// <summary>
        /// 目的行動共通参照
        /// </summary>
        [SerializeField]
        private HoloMonPurposeBehaveReference p_PurposeBehaveReference;
        
        /// <summary>
        /// 反映中の設定データ
        /// </summary>
        [Header("Status")]
        [SerializeField]
        private PurposeInformation p_Info;

        public void AwakeInit(HoloMonBehaveReference behaveReference, HoloMonPurposeBehaveReference purposeBehaveReference)
        {
            p_BehaveReference = behaveReference;
            p_PurposeBehaveReference = purposeBehaveReference;
        }

        private void ApplyData(PurposeInformation a_Porpuse)
        {
            // 設定データの取得
            p_Info = a_Porpuse;
        }

        /// <summary>
        /// ホロモン目的行動種別
        /// </summary>
        /// <returns></returns>
        public HoloMonPurposeType GetHoloMonPurposeType()
        {
            return UniqueHoloMonPurposeType();
        }

        /// <summary>
        /// 行動の開始(async/await制御)
        /// </summary>
        public async UniTask<bool> StartLogicAsync(PurposeInformation a_Purpose)
        {
            ApplyData(a_Purpose);

            var result = await PurposeLogicAsync();

            return true;
        }

        /// <summary>
        /// ホロモン目的行動種別(固有)
        /// </summary>
        /// <returns></returns>
        protected abstract HoloMonPurposeType UniqueHoloMonPurposeType();

        /// <summary>
        /// 行動の開始(固有)
        /// </summary>
        protected abstract UniTask<bool> PurposeLogicAsync();
    }
}

・PurposeStayWaitLogic.cs(待て行動ロジック)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Cysharp.Threading.Tasks;
using UniRx;

using HoloMonApp.Content.Character.Behave.ModeLogic;
using HoloMonApp.Content.Character.Control;
using HoloMonApp.Content.Character.Data.Knowledge.Objects;
using HoloMonApp.Content.Character.View;

namespace HoloMonApp.Content.Character.Behave.Purpose.StayWait
{
    /// <summary>
    /// 待て(おすわり)行動ロジック
    /// </summary>
    public class PurposeStayWaitLogic : PurposeLogicBase
    {
        [Header("Settings")]
        [SerializeField]
        private PurposeStayWaitData p_UniqueData;
        
        private PurposeStayWaitData GetUniqueData => p_UniqueData = (PurposeStayWaitData)this.p_DataInterface;

        /// <summary>
        /// ホロモン目的行動種別
        /// </summary>
        /// <returns></returns>
        protected override HoloMonPurposeType UniqueHoloMonPurposeType()
        {
            return HoloMonPurposeType.StayWait;
        }

        /// <summary>
        /// 待て(おすわり)行動の開始(async/await制御)
        /// </summary>
        protected override async UniTask<bool> PurposeLogicAsync()
        {
            // アクション変数
            ModeLogicResult modeLogicResult;

            // 現在プレイヤーが見えているか否か
            GameObject friendVisionObject = p_View.SensationsFieldOfVisionAPI
                .CheckCollectionByNearDistance(a_ObjectUnderstandType: ObjectUnderstandType.FriendFace)?.Object;

            if (friendVisionObject == null)
            {
                // プレイヤーが見えていない場合

                // 処理を終了する
                return true;
            }

            // おすわりモードのアクションを実行待機する
            modeLogicResult = await p_ActionModeLogic.ActionSitDownAcync(
                a_LookObject: friendVisionObject
                );

            return true;
        }
    }
}

・PurposeJankenLogic.cs(じゃんけん行動ロジック)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Cysharp.Threading.Tasks;
using UniRx;

using HoloMonApp.Content.Character.Behave.ModeLogic;
using HoloMonApp.Content.Character.Behave.ModeLogic.LookAround;
using HoloMonApp.Content.Character.Control;
using HoloMonApp.Content.Character.Data.Knowledge.Objects;
using HoloMonApp.Content.Character.View;

namespace HoloMonApp.Content.Character.Behave.Purpose.Janken
{
    /// <summary>
    /// じゃんけんで遊ぶ行動ロジック
    /// </summary>
    public class PurposeJankenLogic : PurposeLogicBase
    {
        [Header("Settings")]
        [SerializeField]
        private PurposeJankenData p_UniqueData;
        
        private PurposeJankenData GetUniqueData => p_UniqueData = (PurposeJankenData)this.p_DataInterface;

        /// <summary>
        /// ホロモン目的行動種別
        /// </summary>
        /// <returns></returns>
        protected override HoloMonPurposeType UniqueHoloMonPurposeType()
        {
            return HoloMonPurposeType.Janken;
        }

        /// <summary>
        /// じゃんけんで遊ぶ行動の開始(async/await制御)
        /// </summary>
        protected override async UniTask<bool> PurposeLogicAsync()
        {
            // アクション変数
            ModeLogicResult modeLogicResult;

            // 友人に注目する
            ObjectUnderstandType targetType = ObjectUnderstandType.FriendFace;

            // 指定種別のオブジェクトが見えているか否か
            GameObject targetVisionObject = p_View.SensationsFieldOfVisionAPI
                .CheckCollectionByNearDistance(a_ObjectUnderstandType: targetType)?.Object;

            if (targetVisionObject == null)
            {
                // ターゲットが見えていない場合

                // 見回しモードのアクションを実行待機する
                modeLogicResult = await p_ActionModeLogic.ActionLookAroundAcync(
                    a_SearchObjectUnderstandType: targetType
                    );

                // 結果に応じて次のイベントを発生させる
                if (modeLogicResult.FinishModeStatus != HoloMonActionModeStatus.Achievement)
                {
                    // ロジックを達成できなかった場合

                    // 処理を終了する
                    return true;
                }

                // 発見オブジェクトを取得する
                ModeLogicLookAroundReturn lookAroundReturn = (ModeLogicLookAroundReturn)modeLogicResult.ModeLogicReturn;
                targetVisionObject = lookAroundReturn.FindedObject;
            }

            // 振り向きモードのアクションを実行待機する
            modeLogicResult = await p_ActionModeLogic.ActionTurnTargetAcync(
                a_TargetObject: targetVisionObject
                );

            // 結果に応じて次のイベントを発生させる
            if (modeLogicResult.FinishModeStatus != HoloMonActionModeStatus.Achievement)
            {
                // ロジックを達成できなかった場合

                // 処理を終了する
                return true;
            }

            // じゃんけんモードのアクションを実行待機する
            modeLogicResult = await p_ActionModeLogic.ActionJankenAcync();

            // 結果に応じて次のイベントを発生させる
            if (modeLogicResult.FinishModeStatus == HoloMonActionModeStatus.Achievement)
            {
                // ロジックを達成できた場合

                // TODO: この箇所で増加処理を行うべきかは要検討
                // 目的を達成したら機嫌度を増加する
                if (p_View.ConditionsLifeAPI.HumorPercent <= 100)
                {
                    p_Control.ConditionsLifeAPI.AddHumor(10);
                }
            }

            return true;
        }
    }
}

この方法でホロモンの基本行動のロジックをクラスごとに管理するよう実装を見直しました。