using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.AI; using System.Collections.Generic; /// /// プレイヤーの共通ゲージ、時間停止(Codingモード)、UI、および各種バフの制限時間を管理するクラス /// public class PlayerStatusManager : MonoBehaviour { public static PlayerStatusManager Instance { get; private set; } [Header("デバッグ設定")] [Tooltip("チェックを入れると、ゲージが溜まっていなくてもZLZRでCodingModeを開けます(テスト用)")] [SerializeField] private bool ignoreGaugeForDebug = true; [Header("Codingモード用 入力設定")] [SerializeField] private InputActionProperty zlButtonAction; [SerializeField] private InputActionProperty zrButtonAction; [Header("プレイヤー移動・操作制御用 入力設定")] [Tooltip("プレイヤーの移動入力(例: LeftHand Move)のアクションを指定してください")] [SerializeField] private InputActionProperty moveAction; [Tooltip("プレイヤーの視点回転入力(例: RightHand Turn)があれば指定してください(任意)")] [SerializeField] private InputActionProperty turnAction; [Header("パズル制限時間設定")] [Tooltip("CodingModeパズルの制限時間(秒)")] [SerializeField] private float codingLimitDuration = 15f; private float codingTimer = 0f; [Header("ゲージ設定")] [SerializeField] private float maxGauge = 100f; [SerializeField] private float currentGauge = 0f; [Header("表示UI設定")] [SerializeField] private GameObject codingModeUI; [SerializeField] private PuzzleGridBoard puzzleBoard; // 盤面参照 [Header("バフパラメータ設定")] [SerializeField] private float buffDuration = 10f; [SerializeField] private float attackBuffMultiplier = 1.5f; [SerializeField] private float defenseBuffMultiplier = 0.5f; [SerializeField] private float hpHealAmount = 30f; private float attackBuffTimer = 0f; private float defenseBuffTimer = 0f; private bool isCodingMode = false; private List pausedAnimators = new List(); private List pausedAgents = new List(); #region プロパティ public bool IsAttackBuffActive => attackBuffTimer > 0f; public bool IsDefenseBuffActive => defenseBuffTimer > 0f; public float CurrentAttackMultiplier => IsAttackBuffActive ? attackBuffMultiplier : 1.0f; public float CurrentDefenseMultiplier => IsDefenseBuffActive ? defenseBuffMultiplier : 1.0f; #endregion private void Awake() { if (Instance == null) { Instance = this; } else { Destroy(gameObject); } } private void OnEnable() { EnableAction(zlButtonAction); EnableAction(zrButtonAction); EnableAction(moveAction); EnableAction(turnAction); } private void OnDisable() { DisableAction(zlButtonAction); DisableAction(zrButtonAction); DisableAction(moveAction); DisableAction(turnAction); } private void EnableAction(InputActionProperty property) { if (property.action != null) property.action.Enable(); } private void DisableAction(InputActionProperty property) { if (property.action != null) property.action.Disable(); } private void Start() { if (codingModeUI != null) codingModeUI.SetActive(false); } private void Update() { CheckComboInput(); if (!isCodingMode) { UpdateBuffTimers(); } else { // CodingMode中の制限時間カウントダウン codingTimer -= Time.deltaTime; if (codingTimer <= 0f) { FailCodingModeByTimeout(); } } } public void AddGauge(float amount) { if (isCodingMode) return; currentGauge += amount; currentGauge = Mathf.Clamp(currentGauge, 0f, maxGauge); } private void CheckComboInput() { if (zlButtonAction.action == null || zrButtonAction.action == null) return; // 入力値の読み取り float zlVal = zlButtonAction.action.ReadValue(); float zrVal = zrButtonAction.action.ReadValue(); bool zlPressed = zlButtonAction.action.triggered || zlVal > 0.5f; bool zrPressed = zrButtonAction.action.triggered || zrVal > 0.5f; // 両方のトリガーが引かれているか bool isBothHeld = zlVal > 0.5f && zrVal > 0.5f; bool isAnyTriggered = zlButtonAction.action.triggered || zrButtonAction.action.triggered; if (isBothHeld && isAnyTriggered) { if (!isCodingMode) { // ゲージチェック(デバッグフラグがONならゲージ無視で起動) if (ignoreGaugeForDebug || currentGauge >= maxGauge) { StartCodingMode(); } else { Debug.LogWarning($"⚠️ ゲージが足りないためCodingModeを開けません。現在: {currentGauge} / 必要: {maxGauge}"); } } else { // CodingMode中に再度同時押し ➔ キャンセルして無消費で復帰 CancelCodingMode(); } } } private void StartCodingMode() { isCodingMode = true; codingTimer = codingLimitDuration; if (puzzleBoard != null) puzzleBoard.ClearBoard(); DisableAction(moveAction); DisableAction(turnAction); // 敵のアニメーション・NavMesh停止 foreach (var anim in FindObjectsByType(FindObjectsSortMode.None)) { if (anim == null || anim.gameObject == this.gameObject || anim.CompareTag("Player")) continue; anim.speed = 0f; pausedAnimators.Add(anim); } foreach (var agent in FindObjectsByType(FindObjectsSortMode.None)) { if (agent == null || !agent.enabled || !agent.gameObject.activeInHierarchy || agent.CompareTag("Player")) continue; if (!agent.isStopped) { agent.isStopped = true; pausedAgents.Add(agent); } } if (codingModeUI != null) codingModeUI.SetActive(true); Debug.Log($"⏳ Codingモード開始(パズル制限時間: {codingLimitDuration}秒)"); } public void ApplyBuffsAndResume(string buff1, string buff2) { ActivateBuffByName(buff1); ActivateBuffByName(buff2); ResumeWorldState(consumeGauge: true); Debug.Log("🎉 パズル成功!バフを適用して再開。"); } private void FailCodingModeByTimeout() { ResumeWorldState(consumeGauge: true); Debug.Log("💀 時間切れ! Codingモード失敗(バフなし・ゲージ消費)。"); } public void CancelCodingMode() { ResumeWorldState(consumeGauge: false); Debug.Log("↩️ Codingモード手動キャンセル。"); } private void ResumeWorldState(bool consumeGauge) { foreach (var anim in pausedAnimators) { if (anim != null) anim.speed = 1f; } pausedAnimators.Clear(); foreach (var agent in pausedAgents) { if (agent != null && agent.enabled) agent.isStopped = false; } pausedAgents.Clear(); EnableAction(moveAction); EnableAction(turnAction); isCodingMode = false; if (codingModeUI != null) codingModeUI.SetActive(false); if (consumeGauge) currentGauge = 0f; } private void ActivateBuffByName(string buffName) { switch (buffName) { case "AttackUp": attackBuffTimer = buffDuration; break; case "DefenseUp": defenseBuffTimer = buffDuration; break; case "Heal": ExecuteHeal(); break; } } private void ExecuteHeal() { Debug.Log($"💚 HP回復バフ発動! 回復量: {hpHealAmount}"); } private void UpdateBuffTimers() { if (attackBuffTimer > 0f) attackBuffTimer -= Time.deltaTime; if (defenseBuffTimer > 0f) defenseBuffTimer -= Time.deltaTime; } }