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

141 lines
4.7 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;
[Header("--- 드랍 설정 ---")]
[SerializeField] private GameObject potionPrefab;
[SerializeField][Range(0f, 100f)] private float potionDropChance = 30f;
[Space(10)]
[SerializeField] private GameObject[] weaponPrefabs;
[SerializeField][Range(0f, 100f)] private float weaponDropChance = 5f;
2026-01-29 06:58:38 +00:00
protected virtual void Start()
{
currentHP = maxHP;
animator = GetComponent<Animator>();
agent = GetComponent<NavMeshAgent>();
audioSource = GetComponent<AudioSource>();
OnHealthChanged?.Invoke(currentHP, maxHP);
}
2026-01-30 03:24:13 +00:00
// ⭐ [애니메이션 버그 해결] 매 프레임 속도를 체크해서 애니메이터에 전달합니다.
protected virtual void Update()
{
if (isDead) return;
if (agent != null && animator != null)
{
// 에이전트의 현재 이동 속도를 가져와서 "Speed" 파라미터에 넣어줍니다.
float currentSpeed = agent.velocity.magnitude;
animator.SetFloat("Speed", currentSpeed);
}
}
2026-01-29 06:58:38 +00:00
public virtual void TakeDamage(float amount) { OnDamaged(amount); }
public virtual void OnDamaged(float damage)
{
if (isDead) return;
currentHP -= damage;
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;
2026-01-30 03:24:13 +00:00
// 아이템 날아감 방지: 몬스터 시체의 충돌을 끕니다.
Collider col = GetComponent<Collider>();
if (col != null) col.enabled = false;
2026-01-29 06:58:38 +00:00
2026-01-30 03:24:13 +00:00
OnMonsterKilled?.Invoke(expReward);
TryDropItems();
2026-01-29 06:58:38 +00:00
if (agent && agent.isOnNavMesh) { agent.isStopped = true; agent.velocity = Vector3.zero; }
animator.Play(Monster_Die, 0, 0f);
if (deathSound) audioSource.PlayOneShot(deathSound);
Destroy(gameObject, 1.5f);
}
private void TryDropItems()
{
if (potionPrefab != null && UnityEngine.Random.Range(0f, 100f) <= potionDropChance)
{
SpawnItem(potionPrefab);
}
if (weaponPrefabs != null && weaponPrefabs.Length > 0 && UnityEngine.Random.Range(0f, 100f) <= weaponDropChance)
{
int randomIndex = UnityEngine.Random.Range(0, weaponPrefabs.Length);
SpawnItem(weaponPrefabs[randomIndex]);
}
}
private void SpawnItem(GameObject prefab)
{
Vector3 spawnPos = transform.position + Vector3.up * 0.5f;
GameObject item = Instantiate(prefab, spawnPos, Quaternion.identity);
2026-01-30 03:24:13 +00:00
// ✅ [유저 요청] 배율 없이 프리팹의 원래 크기를 100% 그대로 적용
item.transform.localScale = prefab.transform.localScale;
if (item.TryGetComponent<Rigidbody>(out var rb))
{
2026-01-30 03:24:13 +00:00
// 튀어오르는 힘은 유저님이 설정하신 0.02f 유지
Vector3 popDir = Vector3.up * 0.02f + UnityEngine.Random.insideUnitSphere * 0.02f;
rb.AddForce(popDir, ForceMode.Impulse);
if (prefab != potionPrefab)
{
2026-01-30 03:24:13 +00:00
rb.AddTorque(UnityEngine.Random.insideUnitSphere * 0.3f, ForceMode.Impulse);
}
}
}
2026-01-29 06:58:38 +00:00
public void OnDeathAnimEnd() { }
}