using UnityEngine;
///
/// 하이브리드 몬스터 스포너 (생성은 스포너 기준, 생존은 몬스터 기준)
/// - Birth: 스포너 기준 거리로 생성
/// - Life & Hibernate: 몬스터 기준 거리로 최적화
/// - Wake Up: 범위 안으로 복귀 시 재활성화
///
public class MonsterSpawner : MonoBehaviour
{
[Header("=== 생성 설정 (Birth - 스포너 기준) ===")]
[Tooltip("스포너로부터 이 거리 안에 플레이어가 들어오면 몬스터 생성")]
[SerializeField] private float spawnRange = 25f;
[Tooltip("몬스터가 죽은 후 재생성까지 대기 시간")]
[SerializeField] private float respawnCooldown = 3f;
[Tooltip("오브젝트 풀에서 가져올 몬스터 태그")]
[SerializeField] private string mobTag = "NormalMob";
[Header("=== 최적화 설정 (Life & Hibernate - 몬스터 기준) ===")]
[Tooltip("몬스터 본체로부터 이 거리를 벗어나면 강제 동면 (전투 중이어도!)")]
[SerializeField] private float optimizationRange = 60f;
// 내부 상태
private GameObject _myMonster;
private MonsterClass _monsterScript;
private Transform _player;
private float _nextSpawnTime;
private void Start()
{
FindPlayer();
}
private void FindPlayer()
{
GameObject playerObj = GameObject.FindGameObjectWithTag("Player");
if (playerObj != null) _player = playerObj.transform;
}
private void Update()
{
if (_player == null) { FindPlayer(); return; }
// 몬스터가 없거나 죽었으면 -> Birth
if (_myMonster == null || (_monsterScript != null && _monsterScript.IsDead))
{
HandleBirth();
}
// 몬스터가 살아있으면 -> Life & Hibernate
else
{
HandleLifeAndHibernate();
}
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 🐣 BIRTH (생성) - 스포너 기준
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
private void HandleBirth()
{
// ⭐ 스포너 <-> 플레이어 거리
float distanceFromSpawner = Vector3.Distance(transform.position, _player.position);
if (distanceFromSpawner <= spawnRange && Time.time >= _nextSpawnTime)
{
SpawnMonster();
}
}
private void SpawnMonster()
{
_myMonster = GenericObjectPool.Instance.SpawnFromPool(mobTag, transform.position, transform.rotation);
if (_myMonster != null)
{
_monsterScript = _myMonster.GetComponent();
if (_monsterScript != null) _monsterScript.ResetStats();
}
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 💤 LIFE & HIBERNATE (생존/동면) - 몬스터 기준
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
private void HandleLifeAndHibernate()
{
if (_myMonster == null) { _monsterScript = null; return; }
// ⭐ 몬스터 본체 <-> 플레이어 거리
float distanceFromMonster = Vector3.Distance(_myMonster.transform.position, _player.position);
if (distanceFromMonster > optimizationRange)
{
// 😴 HIBERNATE (동면)
HibernateMonster();
}
else
{
// 👁 WAKE UP (기상)
WakeUpMonster();
}
}
private void HibernateMonster()
{
if (_myMonster.activeSelf)
{
_myMonster.SetActive(false);
}
}
private void WakeUpMonster()
{
if (!_myMonster.activeSelf)
{
_myMonster.SetActive(true);
if (_monsterScript != null)
{
// ⭐ AI 복구 (전투 중이었다면 추적 재개)
_monsterScript.Reactivate();
}
}
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 💀 DEATH (사망 처리 및 쿨타임)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
///
/// 몬스터가 죽었을 때 호출 (쿨타임 적용)
///
public void NotifyMonsterDead()
{
// 쿨타임 계산: 현재 시간 + 대기 시간
_nextSpawnTime = Time.time + respawnCooldown;
// 몬스터 참조를 비워서 Update에서 다시 HandleBirth()로 넘어가게 함
_myMonster = null;
_monsterScript = null;
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Gizmos
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
private void OnDrawGizmosSelected()
{
// 스포너 생성 범위 (빨간색)
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, spawnRange);
// 몬스터 최적화 범위 (파란색)
if (_myMonster != null)
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(_myMonster.transform.position, optimizationRange);
}
}
}