주석추가
This commit is contained in:
@@ -1,42 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
// ============================================================================
|
||||
// EnemySpawner
|
||||
// ----------------------------------------------------------------------------
|
||||
// 단순한 적 스폰 컨트롤러 (웨이브 없이 자동 스폰/리스폰).
|
||||
// WaveManager가 시간 제한 스폰이라면, 이건 무한/제한 스폰의 일반 패턴.
|
||||
//
|
||||
// 사용 예시:
|
||||
// - 테스트 씬: Max Alive 1 + Respawn 켜기 → 한 마리씩 무한 등장
|
||||
// - 아레나: Max Alive 5 + Total Limit 20 + Respawn 켜기 → 총 20마리, 동시 5
|
||||
// - 일회성 매복: Spawn On Start 끄고 외부에서 SpawnNow() 호출
|
||||
// ============================================================================
|
||||
public class EnemySpawner : MonoBehaviour
|
||||
{
|
||||
// ─── 스폰 설정 ───────────────────────────────────────────────────────
|
||||
[Header("Spawn Configuration")]
|
||||
[SerializeField] private Enemy _enemyPrefab;
|
||||
[SerializeField] private int _maxAliveCount = 3;
|
||||
[SerializeField] private float _spawnInterval = 2f;
|
||||
[SerializeField] private float _initialDelay = 0f;
|
||||
[SerializeField] private Enemy _enemyPrefab; // 스폰할 적 프리팹
|
||||
[SerializeField] private int _maxAliveCount = 3; // 동시에 살아있을 수 있는 최대 수
|
||||
[SerializeField] private float _spawnInterval = 2f; // 스폰 간격 (초)
|
||||
[SerializeField] private float _initialDelay = 0f; // 첫 스폰 전 대기 시간
|
||||
|
||||
// ─── 위치 설정 ───────────────────────────────────────────────────────
|
||||
[Header("Spawn Position")]
|
||||
[SerializeField] private Transform[] _spawnPoints;
|
||||
[SerializeField] private float _spawnRadius = 0f;
|
||||
[SerializeField] private Transform _enemyParent;
|
||||
[SerializeField] private Transform[] _spawnPoints; // 비워두면 자기 위치, 여러 개면 랜덤 선택
|
||||
[SerializeField] private float _spawnRadius = 0f; // 0보다 크면 spawn point 주변 무작위 분산
|
||||
[SerializeField] private Transform _enemyParent; // 스폰된 적을 묶을 부모 (Hierarchy 정리용)
|
||||
|
||||
// ─── 동작 옵션 ───────────────────────────────────────────────────────
|
||||
[Header("Behavior")]
|
||||
[SerializeField] private bool _spawnOnStart = true;
|
||||
[SerializeField] private bool _respawnOnDeath = true;
|
||||
[SerializeField] private int _totalSpawnLimit = 0;
|
||||
[SerializeField] private bool _spawnOnStart = true; // Start에서 자동 스폰 시작
|
||||
[SerializeField] private bool _respawnOnDeath = true; // 죽으면 자동 리스폰 (false면 일회성)
|
||||
[SerializeField] private int _totalSpawnLimit = 0; // 누적 스폰 한도 (0이면 무제한)
|
||||
|
||||
private readonly List<Enemy> _aliveEnemies = new();
|
||||
private float _nextSpawnTime;
|
||||
private int _totalSpawned;
|
||||
private bool _active;
|
||||
private readonly List<Enemy> _aliveEnemies = new(); // 현재 살아있는 적들 (자동 정리됨)
|
||||
private float _nextSpawnTime; // 다음 스폰 가능 시각
|
||||
private int _totalSpawned; // 지금까지 누적 스폰 수
|
||||
private bool _active; // 스폰 활성 상태
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (_spawnOnStart) BeginSpawning();
|
||||
}
|
||||
|
||||
// 외부 트리거에서 스폰 시작 (예: 플레이어가 영역 진입).
|
||||
public void BeginSpawning()
|
||||
{
|
||||
_active = true;
|
||||
_nextSpawnTime = Time.time + _initialDelay;
|
||||
}
|
||||
|
||||
// 스폰 일시 중지. 살아있는 적은 그대로 유지.
|
||||
public void StopSpawning() => _active = false;
|
||||
|
||||
// 스폰 + 살아있는 적 모두 제거 + 카운터 초기화. 재시작용.
|
||||
public void ResetSpawner()
|
||||
{
|
||||
for (int i = _aliveEnemies.Count - 1; i >= 0; i--)
|
||||
@@ -53,18 +70,21 @@ private void Update()
|
||||
{
|
||||
if (!_active) return;
|
||||
|
||||
// Destroy된 적 참조는 null이 됨. 자동 정리.
|
||||
_aliveEnemies.RemoveAll(e => e == null);
|
||||
|
||||
if (!_respawnOnDeath && _aliveEnemies.Count == 0 && _totalSpawned > 0) return;
|
||||
if (_totalSpawnLimit > 0 && _totalSpawned >= _totalSpawnLimit) return;
|
||||
if (_aliveEnemies.Count >= _maxAliveCount) return;
|
||||
if (Time.time < _nextSpawnTime) return;
|
||||
// 조기 종료 조건들:
|
||||
if (!_respawnOnDeath && _aliveEnemies.Count == 0 && _totalSpawned > 0) return; // 일회성이고 다 죽었으면 끝
|
||||
if (_totalSpawnLimit > 0 && _totalSpawned >= _totalSpawnLimit) return; // 누적 한도 도달
|
||||
if (_aliveEnemies.Count >= _maxAliveCount) return; // 동시 최대치 도달
|
||||
if (Time.time < _nextSpawnTime) return; // 다음 스폰 시간 안 됨
|
||||
if (_enemyPrefab == null) return;
|
||||
|
||||
SpawnOne();
|
||||
_nextSpawnTime = Time.time + _spawnInterval;
|
||||
}
|
||||
|
||||
// 1마리 즉시 스폰. 외부에서 직접 호출 가능 (예: 이벤트 트리거).
|
||||
public Enemy SpawnOne()
|
||||
{
|
||||
if (_enemyPrefab == null) return null;
|
||||
@@ -76,6 +96,10 @@ public Enemy SpawnOne()
|
||||
return enemy;
|
||||
}
|
||||
|
||||
// 스폰 위치 결정:
|
||||
// 1) Spawn Points 있으면 그중 랜덤 선택
|
||||
// 2) 없으면 자기 위치
|
||||
// 3) Spawn Radius > 0이면 위 위치에서 ±radius 무작위 오프셋 추가
|
||||
private Vector3 GetSpawnPosition()
|
||||
{
|
||||
Vector3 basePos;
|
||||
@@ -99,6 +123,8 @@ private Vector3 GetSpawnPosition()
|
||||
return basePos;
|
||||
}
|
||||
|
||||
// Scene 뷰에서 스폰 위치/반경 시각화.
|
||||
// 각 spawn point마다 시안색 원(위치)과 반경 원(분산) 표시.
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
Color pointColor = Color.cyan;
|
||||
|
||||
Reference in New Issue
Block a user