요구명세는 아래와 같다.
- 새로운 웨이브마다 적을 한꺼번에 생성
- 현재 웨이브의 적이 모두 사망시 다음 웨이브로 넘어감
- 웨이브가 증가할 때마다, 생성되는 적의 수 증가
- 적을 생성할 때, 전체 능력치 0%에서 100%까지 랜덤설정
- 게임 오버시, 적 생성 중단
Prefab으로 제공된 Spawn Point를 드래그하자.
(그림에 실수가 있는데, HUD Canvas가 아니라, SpawnPoint를 드래그해야한다)
네 입구를 지정하고 있는것을 확인할수있다.
새 Empty 오브젝트로 EnemySpawner를 만들고, EnemySpawner.cs Script를 추가한다.
EnemySpawner.cs Script를 보자.
EnemySpawner.cs
스폰된 좀비는 Array가 아니라 List로 관리할 것이다. List는, 배열과 다르게 length가 동적으로 변한다는 특징이 있다.
using System.Collections.Generic;
using UnityEngine;
// 적 게임 오브젝트를 주기적으로 생성
public class EnemySpawner : MonoBehaviour {
public Enemy enemyPrefab; // 생성할 적 AI
public Transform[] spawnPoints; // 적 AI를 소환할 위치들
public float damageMax = 40f; // 최대 공격력
public float damageMin = 20f; // 최소 공격력
public float healthMax = 200f; // 최대 체력
public float healthMin = 100f; // 최소 체력
public float speedMax = 3f; // 최대 속도
public float speedMin = 1f; // 최소 속도
public Color strongEnemyColor = Color.red; // 강한 적 AI가 가지게 될 피부색
private List<Enemy> enemies = new List<Enemy>(); // 생성된 적들을 담는 리스트
private int wave; // 현재 웨이브
private void Update() {
// 게임 오버 상태일때는 생성하지 않음
if (GameManager.instance != null && GameManager.instance.isGameover)
{
return;
}
// 적을 모두 물리친 경우 다음 스폰 실행
if (enemies.Count <= 0)
{
SpawnWave();
}
// UI 갱신
UpdateUI();
}
// 웨이브 정보를 UI로 표시
private void UpdateUI() {
// 현재 웨이브와 남은 적의 수 표시
UIManager.instance.UpdateWaveText(wave, enemies.Count);
}
// 현재 웨이브에 맞춰 적을 생성
private void SpawnWave() {
wave++;
int spawnCount = Mathf.RoundToInt(wave * 1.5f); // 웨이브의 1.5배를 반올림한 수만큼 적 생성
for (int i = 0; i < spawnCount; i++)
{
float enemyIntensity = Random.Range(0f, 1f); // 적의 세기를 0%에서 100% 사이로 조정
// 적 생성
CreateEnemy(enemyIntensity);
}
}
// 적을 생성하고 생성한 적에게 추적할 대상을 할당
private void CreateEnemy(float intensity) {
float health = Mathf.Lerp(healthMin, healthMax, intensity); // 체력
float damage = Mathf.Lerp(damageMin, damageMax, intensity); // 공격력
float speed = Mathf.Lerp(speedMin, speedMax, intensity); // 이동 속도
Color skinColor = Color.Lerp(Color.white, strongEnemyColor, intensity); // 피부색은 흰색에서 강해질수록 붉게
Transform spawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)]; // 소환 위치
Enemy enemy = Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation); // 적 생성
enemy.Setup(health, damage, speed, skinColor); // 적 설정
enemies.Add(enemy); // 생성된 적을 리스트에 추가
enemy.onDeath += () => enemies.Remove(enemy); // 적의 사망 이벤트에 리스트에서 제거하는 람다식 등록
enemy.onDeath += () => Destroy(enemy.gameObject, 10f); // 적의 사망 이벤트에 10초 뒤에 파괴하는 람다식 등록
enemy.onDeath += () => GameManager.instance.AddScore(100); // 적의 사망 이벤트에 점수 추가 람다식 등록
}
}
나는 CreateEnemy함수가 불편한데, 왜냐하면
delegate에는 알다시피 input과 output 모두 void 인 함수만 넣을 수 있는데,
읽는 측에서는 input은 void라는걸 알 수 있지만 (()라고 되어있으므로), output이 void인지는 모른다.
나는 이벤트핸들러의 리턴값이 void라는걸 명시적으로 알려주고 싶은데, 그렇다면 아래와 같이 사용가능하다.
이렇게 하면, 비록 갑자기 GameManager의 AddScore 함수가 리턴값을 가지게 바뀌더라도, EnemySpawner.cs 내부에서 Wrapping되는 과정에서 해당 리턴값이 버려지게 되므로 코드수정이 필요없어진다.
// 적을 생성하고 생성한 적에게 추적할 대상을 할당
private void CreateEnemy(float intensity) {
float health = Mathf.Lerp(healthMin, healthMax, intensity); // 체력
float damage = Mathf.Lerp(damageMin, damageMax, intensity); // 공격력
float speed = Mathf.Lerp(speedMin, speedMax, intensity); // 이동 속도
Color skinColor = Color.Lerp(Color.white, strongEnemyColor, intensity); // 피부색은 흰색에서 강해질수록 붉게
Transform spawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)]; // 소환 위치
Enemy enemy = Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation); // 적 생성
enemy.Setup(health, damage, speed, skinColor); // 적 설정
enemies.Add(enemy); // 생성된 적을 리스트에 추가
enemy.onDeath += () => OnEnemyDeath(enemy);
enemy.onDeath += () => DestroyEnemy(enemy);
enemy.onDeath += () => AddScore();
}
private void OnEnemyDeath(Enemy enemy) {
enemies.Remove(enemy);
}
private void DestroyEnemy(Enemy enemy) {
Destroy(enemy.gameObject, 10f);
}
private void AddScore() {
GameManager.instance.AddScore(100);
}
EnemySpawner 컴포넌트를 설정하자.
SpawnPoint 0,1,2,3을 등록하면 된다.
4가지 스폰포인트중에서, 랜덤한 위치에 잘 스폰되는걸 확인가능하다.
'Development > Unity Engine' 카테고리의 다른 글
[Retro유니티] PostProcessing과 최종빌드 (1) | 2024.12.29 |
---|---|
[Retro유니티] 아이템 생성기 및 Item 구현 (1) | 2024.12.29 |
[Retro유니티] HUD Canvas 및 GameManager.cs (0) | 2024.12.28 |
[Retro유니티] NavMesh를 통한 길찾기 구현 및 Enemy.cs 완성 (0) | 2024.12.28 |
[Retro유니티] PlayerHealth.cs 완성 (0) | 2024.12.25 |