Projext/Assets/Scripts/Combat/Components/Health.cs

135 lines
7.2 KiB
C#
Raw Permalink Normal View History

2026-02-12 15:23:25 +00:00
using UnityEngine; // 유니티 엔진의 기본 기능을 불러올거에요 -> UnityEngine을
using UnityEngine.Events; // 유니티 이벤트 기능을 사용할거에요 -> UnityEngine.Events를
using System; // C# 기본 이벤트(Action)를 사용할거에요 -> System을
using System.Collections; // 코루틴을 사용할거에요 -> System.Collections를
/// <summary>
/// 플레이어의 체력, 피격, 무적, 사망을 관리합니다.
/// </summary>
public class PlayerHealth : MonoBehaviour, IDamageable // 클래스를 선언할거에요 -> PlayerHealth를
2026-01-29 06:58:38 +00:00
{
2026-02-12 15:23:25 +00:00
[Header("=== 참조 ===")] // 인스펙터 창에 제목을 표시할거에요 -> === 참조 === 를
[SerializeField] private Stats playerStats; // 변수를 선언할거에요 -> 스탯 스크립트를 playerStats에
2026-02-10 08:04:33 +00:00
2026-02-12 15:23:25 +00:00
[Header("=== 설정 ===")] // 인스펙터 창에 제목을 표시할거에요 -> === 설정 === 을
[SerializeField] private float invincibleDuration = 1.0f; // 변수를 선언할거에요 -> 무적 시간을 invincibleDuration에
[SerializeField] private string hitAnimationName = "Player_Hit"; // 변수를 선언할거에요 -> 피격 애니메이션 이름을 hitAnimationName에
2026-01-29 06:58:38 +00:00
2026-02-12 15:23:25 +00:00
[Header("=== 유니티 이벤트 (인스펙터 연결용) ===")] // 인스펙터 창에 제목을 표시할거에요 -> === 유니티 이벤트 === 를
public UnityEvent OnDieEvent; // 이벤트를 선언할거에요 -> 사망 시 발생할 UnityEvent인 OnDieEvent를
public UnityEvent<float> OnHealthChanged; // 이벤트를 선언할거에요 -> 체력 변경 시 발생할 OnHealthChanged를
2026-01-29 06:58:38 +00:00
2026-02-12 15:23:25 +00:00
// ⭐ [이벤트] += 연산자 오류 방지를 위해 event Action 사용
public event Action OnHitEvent;
public event Action OnHit;
public event Action OnDie;
public event Action OnDead;
2026-01-29 06:58:38 +00:00
2026-02-12 15:23:25 +00:00
// ⭐ [핵심 수정 1] 외부에서 수정 가능하도록 set 권한 개방
public float CurrentHP { get; private set; } // (체력은 함부로 바꾸면 안되니 private set 유지)
2026-01-29 06:58:38 +00:00
2026-02-12 15:23:25 +00:00
// "set 접근자에 액세스할 수 없습니다" 오류 해결 -> private 제거
public bool isInvincible { get; set; } = false;
2026-02-12 15:23:25 +00:00
public bool IsDead { get; private set; } = false; // 사망 여부는 내부에서만 관리
private Animator animator; // 변수를 선언할거에요 -> 애니메이터 컴포넌트를 담을 animator를
// ⭐ [핵심 수정 2] "보호 수준 때문에 액세스 불가" 오류 해결 -> public으로 변경
public bool isHit = false;
private void Awake() // 함수를 실행할거에요 -> 초기화 Awake를
{
animator = GetComponentInChildren<Animator>(); // 컴포넌트를 가져올거에요 -> 자식의 애니메이터를
if (playerStats == null) playerStats = GetComponent<Stats>(); // 조건이 맞으면 가져올거에요 -> 스탯 컴포넌트가 비어있다면 내 몸에서
2026-01-29 06:58:38 +00:00
}
2026-02-12 15:23:25 +00:00
private void Start() // 함수를 실행할거에요 -> 시작 Start를
{
2026-02-12 15:23:25 +00:00
if (playerStats != null) // 조건이 맞으면 실행할거에요 -> 스탯이 있다면
{
2026-02-12 15:23:25 +00:00
CurrentHP = playerStats.MaxHealth; // 값을 초기화할거에요 -> 현재 체력을 최대 체력으로
}
2026-02-12 15:23:25 +00:00
else // 조건이 틀리면 실행할거에요 -> 스탯이 없다면
{
CurrentHP = 100f; // 값을 넣을거에요 -> 기본 체력 100으로
Debug.LogWarning("⚠️ Stats 컴포넌트가 없습니다! 기본 체력 100 적용."); // 경고를 출력할거에요
}
RefreshHealthUI(); // 함수를 실행할거에요 -> 초기 체력 UI 갱신을
}
2026-02-12 15:23:25 +00:00
public void TakeDamage(float damage) // 함수를 선언할거에요 -> 외부에서 호출할 피격 함수 TakeDamage를
2026-01-29 06:58:38 +00:00
{
2026-02-12 15:23:25 +00:00
if (IsDead || isInvincible) return; // 조건이 맞으면 중단할거에요 -> 죽었거나 무적이라면
2026-02-02 15:02:12 +00:00
2026-02-12 15:23:25 +00:00
// 실제 데미지 적용
CurrentHP -= damage; // 값을 뺄거에요 -> 체력에서 데미지를
if (CurrentHP < 0) CurrentHP = 0; // 조건이 맞으면 보정할거에요 -> 체력이 음수가 안 되게 0으로
2026-02-02 15:02:12 +00:00
2026-02-12 15:23:25 +00:00
Debug.Log($"💥 피격! 데미지: {damage}, 남은 체력: {CurrentHP}"); // 로그를 출력할거에요 -> 피격 정보를
2026-02-10 08:04:33 +00:00
2026-02-12 15:23:25 +00:00
RefreshHealthUI(); // 함수를 실행할거에요 -> 체력바 갱신을
2026-02-02 15:02:12 +00:00
2026-02-12 15:23:25 +00:00
if (CurrentHP <= 0) // 조건이 맞으면 실행할거에요 -> 체력이 바닥났다면
{
Die(); // 함수를 실행할거에요 -> 사망 처리 Die를
}
else // 조건이 틀리면 실행할거에요 -> 아직 살았다면
{
StartCoroutine(HitRoutine()); // 코루틴을 실행할거에요 -> 피격 무적/경직 처리를
2026-02-02 15:02:12 +00:00
2026-02-12 15:23:25 +00:00
// 모든 이벤트 호출
OnHit?.Invoke();
OnHitEvent?.Invoke();
}
2026-01-29 06:58:38 +00:00
}
2026-02-12 15:23:25 +00:00
private void Die() // 함수를 선언할거에요 -> 사망 처리 Die를
2026-02-02 15:02:12 +00:00
{
2026-02-12 15:23:25 +00:00
if (IsDead) return; // 조건이 맞으면 중단할거에요 -> 이미 죽었다면
2026-02-02 15:02:12 +00:00
2026-02-12 15:23:25 +00:00
IsDead = true; // 상태를 바꿀거에요 -> 사망 상태를 참으로
2026-02-02 15:02:12 +00:00
2026-02-12 15:23:25 +00:00
OnDieEvent?.Invoke(); // 유니티 이벤트
OnDie?.Invoke(); // C# 이벤트
OnDead?.Invoke(); // C# 이벤트 (호환용)
2026-02-02 15:02:12 +00:00
2026-02-12 15:23:25 +00:00
Debug.Log("💀 플레이어 사망!"); // 로그를 출력할거에요 -> 사망 메시지를
2026-02-02 15:02:12 +00:00
}
2026-02-12 15:23:25 +00:00
public void RefreshHealthUI() // 함수를 선언할거에요 -> UI를 갱신하는 RefreshHealthUI를
2026-01-29 06:58:38 +00:00
{
2026-02-12 15:23:25 +00:00
float ratio = (playerStats != null && playerStats.MaxHealth > 0) ? CurrentHP / playerStats.MaxHealth : 0; // 비율을 계산할거에요 -> 현재 체력 / 최대 체력으로
OnHealthChanged?.Invoke(ratio); // 이벤트를 실행할거에요 -> UI 슬라이더 값을 업데이트하도록
2026-01-29 06:58:38 +00:00
}
2026-02-02 15:02:12 +00:00
2026-02-12 15:23:25 +00:00
private IEnumerator HitRoutine() // 코루틴 함수를 선언할거에요 -> 피격 경직 및 무적 처리 HitRoutine을
2026-02-02 15:02:12 +00:00
{
2026-02-12 15:23:25 +00:00
isHit = true; // 상태를 바꿀거에요 -> 경직 상태를 참으로
isInvincible = true; // 상태를 바꿀거에요 -> 무적 상태를 참으로
2026-02-10 08:04:33 +00:00
2026-02-12 15:23:25 +00:00
if (animator != null)
2026-02-10 08:04:33 +00:00
{
2026-02-12 15:23:25 +00:00
animator.Play(hitAnimationName, 0, 0f); // 재생할거에요 -> 설정된 피격 애니메이션을
2026-02-10 08:04:33 +00:00
}
2026-02-12 15:23:25 +00:00
yield return new WaitForSeconds(0.3f); // 기다릴거에요 -> 경직 시간(0.3초)만큼
isHit = false; // 상태를 바꿀거에요 -> 경직 해제
yield return new WaitForSeconds(invincibleDuration - 0.3f); // 기다릴거에요 -> 남은 무적 시간만큼
isInvincible = false; // 상태를 바꿀거에요 -> 무적 해제
2026-02-02 15:02:12 +00:00
}
2026-02-12 15:23:25 +00:00
public void Heal(float amount) // 함수를 선언할거에요 -> 체력을 회복하는 Heal을
2026-02-02 15:02:12 +00:00
{
2026-02-12 15:23:25 +00:00
if (IsDead) return; // 조건이 맞으면 중단할거에요 -> 죽은 상태라면
CurrentHP += amount; // 값을 더할거에요 -> 체력에 회복량을
if (playerStats != null && CurrentHP > playerStats.MaxHealth) // 조건이 맞으면 실행할거에요 -> 최대 체력을 넘었다면
CurrentHP = playerStats.MaxHealth; // 값을 제한할거에요 -> 최대 체력으로
RefreshHealthUI(); // 함수를 실행할거에요 -> UI 갱신을
Debug.Log($"💚 체력 회복: {amount}, 현재: {CurrentHP}"); // 로그를 출력할거에요 -> 회복 정보를
2026-02-02 15:02:12 +00:00
}
2026-01-29 06:58:38 +00:00
}