68 lines
1.8 KiB
C#
68 lines
1.8 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using System;
|
|||
|
|
|
|||
|
|
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 event Action OnHit, OnDead;
|
|||
|
|
public event Action<float, float> OnHealthChanged;
|
|||
|
|
|
|||
|
|
private float _currentHealth;
|
|||
|
|
|
|||
|
|
private void Start()
|
|||
|
|
{
|
|||
|
|
if (stats != null)
|
|||
|
|
{
|
|||
|
|
_currentHealth = stats.MaxHealth;
|
|||
|
|
OnHealthChanged?.Invoke(_currentHealth, stats.MaxHealth);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 애니메이터가 할당 안 되어 있으면 가져오기
|
|||
|
|
if (animator == null) animator = GetComponent<Animator>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void TakeDamage(float amount)
|
|||
|
|
{
|
|||
|
|
if (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("Player_Hit", 0, 0f);
|
|||
|
|
|
|||
|
|
// ⭐ 안전장치: 0.4초 뒤에는 무조건 경직 해제
|
|||
|
|
CancelInvoke(nameof(OnHitEnd));
|
|||
|
|
Invoke(nameof(OnHitEnd), 0.05f);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ⭐ 애니메이션 이벤트 혹은 Invoke로 호출f
|
|||
|
|
public void OnHitEnd()
|
|||
|
|
{
|
|||
|
|
isHit = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Die()
|
|||
|
|
{
|
|||
|
|
IsDead = true;
|
|||
|
|
Cursor.visible = true;
|
|||
|
|
Cursor.lockState = CursorLockMode.None;
|
|||
|
|
OnDead?.Invoke();
|
|||
|
|
}
|
|||
|
|
}
|