using UnityEngine; using System; using System.Collections; public class PlayerHealth : MonoBehaviour, IDamageable { [Header("=== 참조 ===")] [SerializeField] private Stats stats; [SerializeField] private Animator animator; [SerializeField] private PlayerAttack attackScript; // ⭐ 공격 상태 리셋을 위해 추가 public bool IsDead { get; private set; } public bool isHit { get; private set; } public bool isInvincible; // 대시 중 무적 플래그 // ⭐ 기존 OnHit 이벤트와 아래 OnHit() 함수의 이름 충돌을 피하기 위해 이름을 OnHitEvent로 변경함 public event Action OnHitEvent, OnDead; public event Action OnHealthChanged; private float _currentHealth; private IEnumerator Start() { yield return null; if (stats != null) { _currentHealth = stats.MaxHealth; OnHealthChanged?.Invoke(_currentHealth, stats.MaxHealth); Debug.Log($"[UI Sync] 초기 체력 설정 완료: {_currentHealth}/{stats.MaxHealth}"); } if (animator == null) animator = GetComponent(); // 만약 인스펙터에서 할당 안했다면 자동으로 찾아옴 if (attackScript == null) attackScript = GetComponent(); } public void RefreshHealthUI() { if (stats != null) { _currentHealth = Mathf.Min(_currentHealth, stats.MaxHealth); OnHealthChanged?.Invoke(_currentHealth, stats.MaxHealth); } } public void TakeDamage(float amount) { if (isInvincible || IsDead) return; _currentHealth = Mathf.Max(0, _currentHealth - amount); OnHealthChanged?.Invoke(_currentHealth, stats.MaxHealth); // ⭐ 피격 시 트리거 및 상태 리셋 함수 호출 OnHit(); OnHitEvent?.Invoke(); // 이벤트 발생 if (!IsDead) StartHit(); if (_currentHealth <= 0) Die(); } // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ⭐ [추가] 피격 시 공격 상태 리셋 (핵심!) // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ public void OnHit() { if (animator != null) { // 1. 남아있는 공격 트리거를 강제로 꺼버림 (유령 공격 방지) animator.ResetTrigger("Attack"); // 2. 다른 공격(예: 투척) 트리거가 있다면 그것도 리셋 animator.ResetTrigger("Throw"); } // 3. PlayerAttack 스크립트의 공격 중인 상태 플래그도 강제로 꺼줌 if (attackScript != null) { attackScript.IsAttacking = false; } Debug.Log("[Combat] 피격으로 인해 공격 예약 및 상태가 초기화되었습니다."); } private void StartHit() { isHit = true; // 인스펙터에 적힌 피격 애니메이션 이름(HitAnime) 재생 if (animator != null) animator.Play("HitAnime", 0, 0f); CancelInvoke(nameof(OnHitEnd)); Invoke(nameof(OnHitEnd), 0.25f); } public void OnHitEnd() { isHit = false; } private void Die() { IsDead = true; Cursor.visible = true; Cursor.lockState = CursorLockMode.None; OnDead?.Invoke(); } public void Heal(float amount) { if (IsDead) return; _currentHealth = Mathf.Min(_currentHealth + amount, stats.MaxHealth); OnHealthChanged?.Invoke(_currentHealth, stats.MaxHealth); } }