Unity Chapter 11-21. 좀비 TPS 게임 만들기 : Enemy Spawner

Date:     Updated:

카테고리:

태그:

인프런에 있는 이제민님의 레트로의 유니티 C# 게임 프로그래밍 에센스 강의를 듣고 정리한 필기입니다. 😀
🌜 [레트로의 유니티 C# 게임 프로그래밍 에센스] 강의 들으러 가기!


Chapter 11. 좀비 TPS 게임 만들기

📜EnemySpawner.cs

📂Assets/Prefabs 에 있는 🟦Spawner 를 Hierarchy 창에 옮겨주자. 이 Spawner에 📜EnemySpawner.cs가 미리 붙어있다.

  • 🟦Spawner
    • 빈 게임 오브젝트 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 등이 사용될 것이다.
    • 좀비 한명 한명을 밑에 후술할 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에 할당
  • 프리팹으로부터 좀비를 생성
    • enemy = Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation);
  • 생성한 적에게 능력치와 추적 대상 부여해주기
    • enemy.Setup(health, damage, speed, speed * 0.3f, skinColor);
      • 📜Enemy.cs의 Setup 함수
      • 추적 속도는 속도의 30 퍼센트
  • 생성된 이 좀비를 리스트에 추가
    • enemies.Add(enemy);
  • 생성한 좀비가 나중에 사망했을 때의 처리를 위하여 📜LivingEntity 라면 공통적으로 가지고 있는 OnDeath 이벤트에 사망시 실행할 함수들을 미리 등록해둠. 함수 이름, 즉 함수 포인터로 등록을 해야 하기 때문에 실행할 처리들을 람다 함수로 묶어 등록해주었다. 람다 함수는 함수 포인터로 많이 쓰임
    • 사망한 좀비를 리스트에서 제거
      • enemies.Remove(enemy); 를 수행하는 익명 메서드(람다 함수)를 OnDeath 이벤트에 등록
        • List 의 내장함수인 Remove
    • 사망한 좀비를 10 초 뒤에 파괴
      • Destroy(enemy.gameObject, 10f); 를 수행하는 익명 메서드(람다 함수)를 OnDeath 이벤트에 등록
    • 좀비 사망시 점수가 100점만큼 상승하도록
      • GameManager.Instance.AddScore(100); 를 수행하는 익명 메서드(람다 함수)를 OnDeath 이벤트에 등록


🔔 컴포넌트 설정

  • Zombie 오브젝트를 📂Assets/Prefabs 에 옮겨 프리팹으로 만든 후 Hierarcy와 Scene에 존재해있는 Zombie 오브젝트는 삭제하자
    • 프리팹으로 옮기기전 Overrides all 꼭 해주기
  • enemyPrefab에 🟦Zombie 프리팹 넣어주기
    • image


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기


Unity Lesson 1 카테고리 내 다른 글 보러가기

댓글 남기기