Projext/Assets/Scripts/Combat/Components/Health.cs
2026-02-02 17:30:23 +09:00

65 lines
2.3 KiB
C#

using UnityEngine;
using System;
using System.Collections; // ⭐ IEnumerator 사용을 위해 추가
public class PlayerHealth : MonoBehaviour, IDamageable
{
[SerializeField] private Stats stats;
[SerializeField] private Animator animator;
public bool IsDead { get; private set; }
public bool isHit { get; private set; }
public bool isInvincible; // 대시 중 무적 플래그
public event Action OnHit, OnDead;
public event Action<float, float> OnHealthChanged;
private float _currentHealth;
// ⭐ [수정] Start를 코루틴으로 변경하여 실행 순서 문제를 해결합니다.
private IEnumerator Start()
{
// 모든 오브젝트가 깨어날 때까지 한 프레임 기다립니다.
yield return null;
if (stats != null)
{
_currentHealth = stats.MaxHealth;
// 이제 UI가 확실히 준비되었으므로 수치를 전달합니다.
OnHealthChanged?.Invoke(_currentHealth, stats.MaxHealth);
Debug.Log($"<color=cyan>[UI Sync]</color> 초기 체력 설정 완료: {_currentHealth}/{stats.MaxHealth}");
}
if (animator == null) animator = GetComponent<Animator>();
}
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?.Invoke();
if (!IsDead) StartHit();
if (_currentHealth <= 0) Die();
}
private void StartHit()
{
isHit = true;
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); }
}