Unity Chapter 11-21. 좀비 TPS 게임 만들기 : Enemy Spawner
카테고리: Unity Lesson 1
태그: Unity Game Engine
인프런에 있는 이제민님의 레트로의 유니티 C# 게임 프로그래밍 에센스 강의를 듣고 정리한 필기입니다. 😀
🌜 [레트로의 유니티 C# 게임 프로그래밍 에센스] 강의 들으러 가기!
Chapter 11. 좀비 TPS 게임 만들기
📜EnemySpawner.cs
📂Assets/Prefabs 에 있는 🟦Spawner 를 Hierarchy 창에 옮겨주자. 이
Spawner
에 📜EnemySpawner.cs가 미리 붙어있다.
- 🟦Spawner
- 빈 게임 오브젝트 5 개가 자식으로 붙어있다.
- 이 5 개 오브젝트들이 각각 좀비가 스폰될 위치들을 미리 지정해둔 것들이다
- 빈 게임 오브젝트 5 개가 자식으로 붙어있다.
using System.Collections.Generic;
using UnityEngine;
// 적 게임 오브젝트를 주기적으로 생성
public class EnemySpawner : MonoBehaviour
{
private readonly List<Enemy> enemies = new List<Enemy>(); // 생성된 적들을 담는 리스트
public float damageMax = 40f; // 최대 공격력
public float damageMin = 20f; // 최소 공격력
public Enemy enemyPrefab; // 생성할 적 AI
public float healthMax = 200f; // 최대 체력
public float healthMin = 100f; // 최소 체력
public Transform[] spawnPoints; // 적 AI를 소환할 위치들
public float speedMax = 12f; // 최대 속도
public float speedMin = 3f; // 최소 속도
public Color strongEnemyColor = Color.red; // 강한 적 AI가 가지게 될 피부색
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()
{
// 웨이브 1 증가
wave++;
// 현재 웨이브 * 1.5에 반올림 한 개수 만큼 적을 생성
var spawnCount = Mathf.RoundToInt(wave * 5f);
// spawnCount 만큼 적을 생성
for (var i = 0; i < spawnCount; i++)
{
// 적의 세기를 0%에서 100% 사이에서 랜덤 결정
var enemyIntensity = Random.Range(0f, 1f);
// 적 생성 처리 실행
CreateEnemy(enemyIntensity);
}
}
// 적을 생성하고 생성한 적에게 추적할 대상을 할당
private void CreateEnemy(float intensity)
{
// intensity를 기반으로 적의 능력치 결정
var health = Mathf.Lerp(healthMin, healthMax, intensity);
var damage = Mathf.Lerp(damageMin, damageMax, intensity);
var speed = Mathf.Lerp(speedMin, speedMax, intensity);
// intensity를 기반으로 하얀색과 enemyStrength 사이에서 적의 피부색 결정
var skinColor = Color.Lerp(Color.white, strongEnemyColor, intensity);
// 생성할 위치를 랜덤으로 결정
var spawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)];
// 적 프리팹으로부터 적 생성
var enemy = Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation);
// 생성한 적의 능력치와 추적 대상 설정
enemy.Setup(health, damage, speed, speed * 0.3f, skinColor);
// 생성된 적을 리스트에 추가
enemies.Add(enemy);
// 적의 onDeath 이벤트에 익명 메서드 등록
// 사망한 적을 리스트에서 제거
enemy.OnDeath += () => enemies.Remove(enemy);
// 사망한 적을 10 초 뒤에 파괴
enemy.OnDeath += () => Destroy(enemy.gameObject, 10f);
// 적 사망시 점수 상승
enemy.OnDeath += () => GameManager.Instance.AddScore(100);
}
}
멤버 변수
private readonly List<Enemy> enemies = new List<Enemy>(); // 생성된 적들을 담는 리스트
public float damageMax = 40f; // 최대 공격력
public float damageMin = 20f; // 최소 공격력
public Enemy enemyPrefab; // 생성할 적 AI
public float healthMax = 200f; // 최대 체력
public float healthMin = 100f; // 최소 체력
public Transform[] spawnPoints; // 적 AI를 소환할 위치들
public float speedMax = 12f; // 최대 속도
public float speedMin = 3f; // 최소 속도
public Color strongEnemyColor = Color.red; // 강한 적 AI가 가지게 될 피부색
private int wave; // 현재 웨이브
enemies
- 생성된 적들을 담는 리스트. 실행 중 동적으로 담긴다.
- 밑에 후술할 CreateEnemy 함수를 사용하여 적 한명 한명을 생성 후 리스트에 추가할 것!
readonly
, 즉 런타임 상수이기 때문에 한번 리스트 원소들이 정해지면 즉 초기화 되고 나면 바꿀 수 없다. 그 이후엔 덮어 쓸 수 없음.- 이 포스트 참고
- 생성된 적들을 담는 리스트. 실행 중 동적으로 담긴다.
damageMax
,damageMin
- 공격력 범위
enemyPrefab
- 오브젝트로 생성할 좀비(AI) 프리팹을 여기에 할당할 것임
healthMax
,healthMin
- 체력 범위
spawnPoints
배열- 좀비(AI)를 소환할 Transform들 (위치, 회전, 크기)
speedMax
,speedMin
- 속도 범위
strongEnemyColor
- 가장 강한 좀비가 가지게 될 피부색.
- 빨간색으로 초기화 되어 있다.
- 강할 수록 빨간색에 가깝게 할 것이다.
wave
- 현재 웨이브
- 이 값이 늘어나면 늘어날 수록 더 많은 양의 좀비가 스폰되게끔.
멤버 함수
private void Update()
현재 상태에 따라서 좀비를 스폰
private void Update()
{
// 게임 오버 상태일때는 생성하지 않음
if (GameManager.Instance != null && GameManager.Instance.isGameover) return;
// 적을 모두 물리친 경우 다음 스폰 실행
if (enemies.Count <= 0) SpawnWave();
// UI 갱신
UpdateUI();
}
- 게임 매니저 싱글톤이 존재하고 동시에 게임 오버 상태라면
- 좀비 스폰 처리를 실행하지 않고 바로
return
- 즉, 게임 오버 상태가 아닐 때만 좀비를 스폰한다.
- 좀비 스폰 처리를 실행하지 않고 바로
- 적을 모두 물리친 경우에는 다음 스폰을 실행한다.
- 적이 다 죽어야지만 다음 wave로 넘어감
- if (enemies.Count <= 0) SpawnWave();
- 밑에 후술할 SpawnWave() 함수 실행
- 매 프레임마다 UI 갱신
- 밑에 후술할 UpdateUI() 함수 실행
private void UpdateUI()
현재의 웨이브 정보를 UI로 표시
// 웨이브 정보를 UI로 표시
private void UpdateUI()
{
// 현재 웨이브와 남은 적의 수 표시
UIManager.Instance.UpdateWaveText(wave, enemies.Count);
}
- 📜UIManager 싱글톤을 사용하여 현재 웨이브와 남은 적의 수 UI 갱신
private void SpawnWave()
현재 웨이브에 따라 실제로 여러 좀비들을 웨이브 무더기로 스폰
// 현재 웨이브에 맞춰 적을 생성
private void SpawnWave()
{
// 웨이브 1 증가
wave++;
// 현재 웨이브 * 5 에 반올림 한 개수 만큼 적을 생성
var spawnCount = Mathf.RoundToInt(wave * 5f);
// spawnCount 만큼 적을 생성
for (var i = 0; i < spawnCount; i++)
{
// 적의 세기를 0%에서 100% 사이에서 랜덤 결정
var enemyIntensity = Random.Range(0f, 1f);
// 적 생성 처리 실행
CreateEnemy(enemyIntensity);
}
}
wave
1 증가시킴- 현재 웨이브를 5 곱한 개수로 좀비를 스폰할 것이다. 생성할 좀비 수인
spawnCount
결정- 반올림 해주는 이유는 뭐 5.5 같은 소수점 있는 실수를 곱할 때 사용하려고!
spawnCount
만큼 적을 생성enemyIntensity
생설할 적의 능력치. 0 % ~ 100 % 사이에서 랜덤하게 결정.- 0 % 일 때는 최소값인
damageMin
,healthMin
,speedMin
등이 사용될 것이다. - 100 % 일 때는 최대값인
damageMax
,healthMax
,speedMax
등이 사용될 것이다.
- 0 % 일 때는 최소값인
- 좀비 한명 한명을 밑에 후술할 CreateEnemy 함수로 생성해준다.
private void CreateEnemy(float intensity)
좀비 한명 한명을 생성하는 함수.
// 적을 생성하고 생성한 적에게 추적할 대상을 할당
private void CreateEnemy(float intensity)
{
// intensity를 기반으로 적의 능력치 결정
var health = Mathf.Lerp(healthMin, healthMax, intensity);
var damage = Mathf.Lerp(damageMin, damageMax, intensity);
var speed = Mathf.Lerp(speedMin, speedMax, intensity);
// intensity를 기반으로 하얀색과 enemyStrength 사이에서 적의 피부색 결정
var skinColor = Color.Lerp(Color.white, strongEnemyColor, intensity);
// 생성할 위치를 랜덤으로 결정
var spawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)];
// 적 프리팹으로부터 적 생성
var enemy = Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation);
// 생성한 적의 능력치와 추적 대상 설정
enemy.Setup(health, damage, speed, speed * 0.3f, skinColor);
// 생성된 적을 리스트에 추가
enemies.Add(enemy);
// 적의 onDeath 이벤트에 익명 메서드 등록
// 사망한 적을 리스트에서 제거
enemy.OnDeath += () => enemies.Remove(enemy);
// 사망한 적을 10 초 뒤에 파괴
enemy.OnDeath += () => Destroy(enemy.gameObject, 10f);
// 적 사망시 점수 상승
enemy.OnDeath += () => GameManager.Instance.AddScore(100);
}
- 인수
intensity
- 0 % 면 좀비의 능력치가 최소. 크면 클수록 좀비의 능력치가 크다는 것을 의미.
intensity
를 기반으로- 적의 능력치 결정
health
👉 체력 범위의intensity
만큼의 값damage
👉 공격력 범위의intensity
만큼의 값speed
👉 속도 범위의intensity
만큼의 값
- 적의 색깔 결정
skinColor
👉 색깔 범위(하얀색, 빨간색 사이)의intensity
만큼의 값
- 적의 능력치 결정
- 좀비를 생성할 위치를 랜덤으로 결정
- 좀비들을 소환할 각각의 랜덤한 Transform들이 담겨있는
spawnPoints
배열에서 랜덤한 원소를 뽑아spawnPoint
에 할당
- 좀비들을 소환할 각각의 랜덤한 Transform들이 담겨있는
- 프리팹으로부터 좀비를 생성
enemy
= Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation);
- 생성한 적에게 능력치와 추적 대상 부여해주기
- enemy.Setup(health, damage, speed, speed * 0.3f, skinColor);
- 📜Enemy.cs의 Setup 함수
- 추적 속도는 속도의 30 퍼센트
- enemy.Setup(health, damage, speed, speed * 0.3f, skinColor);
- 생성된 이 좀비를 리스트에 추가
- enemies.Add(enemy);
- 생성한 좀비가 나중에 사망했을 때의 처리를 위하여 📜LivingEntity 라면 공통적으로 가지고 있는
OnDeath
이벤트에 사망시 실행할 함수들을 미리 등록해둠. 함수 이름, 즉 함수 포인터로 등록을 해야 하기 때문에 실행할 처리들을 람다 함수로 묶어 등록해주었다. 람다 함수는 함수 포인터로 많이 쓰임- 사망한 좀비를 리스트에서 제거
- enemies.Remove(enemy); 를 수행하는 익명 메서드(람다 함수)를
OnDeath
이벤트에 등록- List 의 내장함수인 Remove
- enemies.Remove(enemy); 를 수행하는 익명 메서드(람다 함수)를
- 사망한 좀비를 10 초 뒤에 파괴
- Destroy(enemy.gameObject, 10f); 를 수행하는 익명 메서드(람다 함수)를
OnDeath
이벤트에 등록
- Destroy(enemy.gameObject, 10f); 를 수행하는 익명 메서드(람다 함수)를
- 좀비 사망시 점수가 100점만큼 상승하도록
- GameManager.Instance.AddScore(100); 를 수행하는 익명 메서드(람다 함수)를
OnDeath
이벤트에 등록
- GameManager.Instance.AddScore(100); 를 수행하는 익명 메서드(람다 함수)를
- 사망한 좀비를 리스트에서 제거
🔔 컴포넌트 설정
Zombie
오브젝트를 📂Assets/Prefabs 에 옮겨 프리팹으로 만든 후 Hierarcy와 Scene에 존재해있는Zombie
오브젝트는 삭제하자- 프리팹으로 옮기기전 Overrides all 꼭 해주기
enemyPrefab
에 🟦Zombie 프리팹 넣어주기
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기