Projext/Assets/Scripts/Combat/Components/Health.cs
2026-02-03 00:02:12 +09:00

111 lines
3.7 KiB
C#

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<float, float> OnHealthChanged;
private float _currentHealth;
private IEnumerator Start()
{
yield return null;
if (stats != null)
{
_currentHealth = stats.MaxHealth;
OnHealthChanged?.Invoke(_currentHealth, stats.MaxHealth);
Debug.Log($"<color=cyan>[UI Sync]</color> 초기 체력 설정 완료: {_currentHealth}/{stats.MaxHealth}");
}
if (animator == null) animator = GetComponent<Animator>();
// 만약 인스펙터에서 할당 안했다면 자동으로 찾아옴
if (attackScript == null) attackScript = GetComponent<PlayerAttack>();
}
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("<color=yellow>[Combat]</color> 피격으로 인해 공격 예약 및 상태가 초기화되었습니다.");
}
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);
}
}