Projext/Assets/7.Other Code/MonsterClass.cs

86 lines
2.9 KiB
C#
Raw Normal View History

2026-01-29 06:58:38 +00:00
using UnityEngine;
using UnityEngine.AI;
using System;
public class MonsterClass : MonoBehaviour, IDamageable
{
[Header("스탯")]
[SerializeField] protected float maxHP = 100f;
protected float currentHP;
public event Action<float, float> OnHealthChanged;
[Header("피격 / 사망 애니메이션")]
[SerializeField] protected string Monster_GetDamage = "Monster_GetDamage";
[SerializeField] protected string Monster_Die = "Monster_Die";
protected Animator animator;
protected NavMeshAgent agent;
protected AudioSource audioSource;
protected bool isHit;
protected bool isDead;
[Header("경험치")]
[SerializeField] protected int expReward = 10;
public static System.Action<int> OnMonsterKilled;
[Header("공통 사운드/이펙트")]
[SerializeField] protected AudioClip hitSound;
[SerializeField] protected AudioClip deathSound;
[SerializeField] protected GameObject deathEffectPrefab;
[SerializeField] protected ParticleSystem hitEffect;
[SerializeField] protected Transform impactSpawnPoint;
protected virtual void Start()
{
currentHP = maxHP;
animator = GetComponent<Animator>();
agent = GetComponent<NavMeshAgent>();
audioSource = GetComponent<AudioSource>();
OnHealthChanged?.Invoke(currentHP, maxHP);
}
// ⭐ 핵심: 부모에서 virtual을 붙여야 NormalMonster에서 에러가 안 납니다.
public virtual void TakeDamage(float amount) { OnDamaged(amount); }
public virtual void OnDamaged(float damage)
{
if (isDead) return;
currentHP -= damage;
Debug.Log($"{gameObject.name} 피격! 체력: {{{currentHP}/{maxHP}}}");
OnHealthChanged?.Invoke(currentHP, maxHP);
if (currentHP <= 0) { Die(); return; }
if (!isHit) StartHit();
}
protected virtual void StartHit()
{
isHit = true;
if (agent && agent.isOnNavMesh) { agent.isStopped = true; agent.velocity = Vector3.zero; }
animator.Play(Monster_GetDamage, 0, 0f);
if (hitEffect) hitEffect.Play();
if (hitSound) audioSource.PlayOneShot(hitSound);
}
public virtual void OnHitEnd() { isHit = false; if (agent && agent.isOnNavMesh) agent.isStopped = false; }
protected virtual void Die()
{
if (isDead) return;
isDead = true;
// ⭐ 핵심 수정: 애니메이션 신호 기다리지 말고 즉시 처리
Debug.Log($"{gameObject.name} 사망! 경험치 {expReward} 지급 및 1.5초 후 파괴.");
OnMonsterKilled?.Invoke(expReward);
if (agent && agent.isOnNavMesh) { agent.isStopped = true; agent.velocity = Vector3.zero; }
animator.Play(Monster_Die, 0, 0f);
if (deathSound) audioSource.PlayOneShot(deathSound);
// 1.5초 뒤 자동 삭제 (이벤트 씹힘 방지)
Destroy(gameObject, 1.5f);
}
// 에러 방지용으로 남겨만 둠
public void OnDeathAnimEnd() { }
}