본문 바로가기
게임 개발/유니티 게임 개발 일지

#16 UIManager, GameManager, EnemySpawner 구현

by FlowTree 2020. 8. 9.
반응형

0.작성하기 전 여담

유니티 게임 개발 일지를 작성하는 이유는 작성한 경험을 잊지 않기와 시스템 기획서 작성 연습인데 매 번 글을 작성할 때마다 시원 시원하게 작성이 잘 안된다. 그래서 이미 구현한 기능들이지만 유니티를 켜서 확인하고, 스크립트를 확인해서 구성요소(데이터 = 변수, 파라미터, 리소스), 각각의 기능들을 다시 한번 확인하고 정리해서 글을 작성한다.

 

이런 방법이 과연 현업에서도 통할까? 아니라고 본다. 왜냐 보통 시스템 기획은 게임 작동에 중요한 기능들을 기획하는 것이기 때문에 구현하기 전까지 확인할 수 가 없다. 따라서 상상력이 좋아서 머릿 속에서 완벽하게 실행검증하여 시스템을 기획하거나 아니면 시스템 기획 경험(실행 검증의 경험, 이러면 충분하다, 부족하다를 앎)이 풍부하다면, 추가적으로 다양한 게임을 플레이하고 그 게임들의 시스템을 잘 파악하고 있다면 수월하게 시스템 기획서를 작성이 가능하겠지만

 

나는 그런 상황이 아니다 보니 시스템 기획서를 작성하는데 시간이 걸리는 문제가 발생할 것이고 잘 작성이 안되서 스트레스를 많이 받을 것이다.(슬프다, 지금도 스트레스 받고 있음, 근데 요즘은 스트레스 버티기 터득함 잠깐 운동+명상으로 푼다, 예전엔 산책으로 풀었음, 잡설이 긴데 개인 블로그니까 써도 되지ㅋㅋ)

 

위의 수월하게 시스템 기획서를 작성하는 법의 공통점을 보면 머릿 속에 작성할, 구현할 시스템을 알고 있다는 것이다.

내가 만약 머릿 속에 구현할 시스템을 잘 알고 있다면? 어떻게? 바로 정보들을 구조화 하는 것이다. 많은 정보들을 쉽게 기억하려면 정보들을 구조화해서 이해하면 수월하다. 예전에 내가 암기력이 너무 안좋아서 어떻게 하면 극복할 수 있을까 정보를 수집한 결과(슈퍼 기억력의 비밀, 넷플릭스 기억의 궁전) 정보들을 기억의 틀에 넣고 연상법을 이용했다.

 

기억력 챔피언들은 자신들이 머릿 속에서 쉽게 떠올릴 수 있는 익숙한 공간(자신들 방이라던가) 또는 주제, 관심 분야, 스토리를 짓거나 등 자신들에게 익숙한 것들을 기억을 담는 틀로 삼고 거기에 외울 정보들을 채워넣어 연결시켜서 암기한다.

 

기억을 담는 틀과 기억할 정보를 연결 = 구현할 시스템의 기능들을 구조화와 상위 카테고리 = 기억을 담는 틀, 하위 카테고리 = 기억할 정보, 이렇게 시스템 기획 내용을 머릿 속에 정리한다면 작성해야할 내용들을 잘 기억할 수 있을 것 같다.

 

구조화한 상위 카테고리는 하위 카테고리의 내용을 담기 때문에 개수도 적고 추상화된 내용들이기 때문에 기억하기도 좋다. 그리고 상위 카테고리를 보고 하위 카테고리를 연상하기 쉽다. 반대로 하위 카테고리를 보고 상위 카테고리도 연상하기 쉽다. 정보들이 구조로 연결되어있기 때문이다.

 

시스템이 도식화되어 있다면 시각적 정보이기 때문에 기억하기 더욱 쉬울 것이다(글보다 시각적인 정보를 떠올리기 쉽다). 시스템을 구조화하여 구조도, 플로우차트를 미리 만들어 둔다면 화면에 띄워놓고 보면서 할 수도 있다. 작성하면서 까먹고 빠진 내용, 수정해야할 내용들이 있겠지만 적어도 구조도에 있는 걸 잊진 않을 것이다.

(그래도 구조도, 플로우차트는 바로 수정하기 = 안그러면 정보가 섞여서 시간 낭비 가능성 있음)

 

그래서 유니티 게임 개발 일지를 작성하기 전에 미리 시스템을 구조도와 플로우차트를 먼저 작성해서 구조화하고 머릿 속에 넣어 두자. 그러면 보다 수월하게 글을 작성 할 수 있을 것이고, 이런 게 기획서 작성의 패턴화가 된다면 현업에서 잘 적응할 수 있을 것이다.

 

사실 예전에 구조도랑 플로우 차트를 먼저 작성하고 블로그 글을 작성한 것 같은데 어느샌가 까먹고 글의 카테고리 먼저 써두고 유니티랑 스크립트 보면서 내용 빼오고 작성했다. 역시 적어둬야... 물론 노트에 이 방법을 적어둔것 같은데 찾기 힘드니 인터넷에 한 번 더 정리함

 

#(중요)기능을 구조화하기 전에 어떤 기능들이 있고 어떻게 기능들을 묶을지는(라벨링) 어떤 내용들이 있는지를 알아야한다. 따라서 어떤 시스템을 기획할 때 필요한 정보들을 먼저 나열을 해야지(구현, 기획에 필요한 모든 데이터를 알아야 함 그래야 그룹핑, 구조화 가능) 정보, 기능들을 구조화가 가능하다.


1.기능 정의

1.1.UIManager

  • UIManager는 현재 점수를 알려주는 ScoreUI, 현재 웨이브 단계를 알려주는 WaveUI, 플레이어가 사망 시 게임 오버를 알려주는 GameoverUI를 관리하는 매니저이다.
  • ScoreUI: 적 처치 시 현재 획득 점수를 UI에 업데이트
  • WaveUI: 웨이브 시작 시 현재 웨이브 단계를 UI에 업데이트
  • GameoverUI
    -플레이어 사망 시 게임 오버UI, Restart 버튼 출력
    -Restart버튼 입력 시 게임 재시작

 

1.2.GameManager

  • 게임 진행 규칙들을 관리하는 매니저이다.
  • 게임 오버 관리: 플레이어 사망 시 사망 상태를 적용하여 게임 오버를 관리한다.
  • 게임 오버UI 활성화: 플레이어가 사망 상태 시 UIManager에 접근하여 GameoverUI를 출력한다.
  • 점수 획득: 플레이어가 적을 처치 시 해당 적의 점수를 획득한다.
  • 초기 점수 설정: 게임 시작 시 초기 점수(0점)을 설정한다.

 

1.3.EnemySpawner 

  • 웨이브가 시작 시 적 생성 포인트에 적을 생성하는 기능이다.
  • 적의 능력치(체력, 데미지, 속도, 공격 사거리)와 적 처치 시 획득 점수를 설정하는 기능이다.
  • 웨이브 관리를 하는 기능이다.

2.기획의도

2.1.UIManager

  • 여러 UI의 스크립트를 한 곳에서 쉽게 관리하기

 

2.2.GameManager

  • 게임 코어 규칙을 쉽게 구현, 관리하기

 

2.3.EnemySpawner

  • 적을 생성할 때 필요한 요소들을 쉽고 한 곳에서 관리하여 조작, 개선 편의성 제공
  • 적의 능력치 설정하는 기능을 통해 새로운 웨이브가 시작할 때 일정 범위 내에서 적들의 세기를 다르게하여 플레이어에게 다양한 난이도 제공

3.기능 명세

3.1.기능 구조도

UIManager 기능 구조도

 

GameManager 기능 구조도

 

EnemySpawner 기능 구조도

 

3.2.플로우차트

#단순한 기능들은 쉽게 규칙으로 설명할 수 있는데, 플로우차트를 작성하니 시간이 더 걸려서 생략함

#기능에는 어떤 하위 기능들이 있는지 기능 구조도 정도만 알려줘도 될 것 같다.

 

3.3.UI 위치

ScoreUI, WaveUI

GameoverUI

 

3.4.세부 기능

3.4.1.UIManager

3.4.1.1.ScoreUI

  • 게임 플레이 시 현재 점수를 게임 화면에 출력하는 기능

●UI 정보와 파라미터

이름 내용
ScoreUI 위치 게임 화면 상단의 중앙
점수 초기값 0
ScoreUI 텍스트 크기 40
ScoreUI 텍스트 색상 노랑
ScoreUI 텍스트 내용 현재 점수(GameManager의 Score 값)

●규칙

  • 현재 점수 출력: GameManager에서 현재 점수 값을 전달받아서 ScoreUI에 출력한다.

 

3.4.1.2.WaveUI

  • 게임 플레이 시 현재 웨이브 단계를 게임 화면에 출력하는 기능
  • 게임 플레이 시 현재 웨이브에서 남은 적 수를 화면에 출력하는 기능

●UI 정보와 파라미터

이름 내용
WaveUI 웨이브 텍스트 위치 게임 화면 상단의 우측
WaveUI 웨이브 웨이브 단계 초기값  1
WaveUI 웨이브 텍스트 크기 30
WaveUI 웨이브 텍스트 색상 노랑
WaveUI 웨이브 텍스트 내용 현재 웨이브 단계(EnemySpawner의 wave값)
WaveUI 남은 적 수 텍스트 위치 WaveUI Text 위치의 아래
WaveUI 남은 적 수 텍스트 크기 30
WaveUI 남은 적 수 텍스트 색상 노랑
WaveUI 남은 적 수 텍스트 내용 현재 웨이브 단계에서 남은 적 수
(EnemySpawner의 allEnemyCount 값)

●규칙

  • 현재 웨이브 단계 출력: EnemySpawner에서 웨이브 값을 전달받아서 Wave Text에 출력한다. 
  • 현재 남은 적 수 출력: EnemySpanwer의 남은 적 수 값을 받아서 남은 적 수 Text에 값을 출력한다.

 

3.4.1.3.GameoverUI

  • 플레이어가 사망 시 게임 오버를 알려주는 UI
  • GameoverUI의 Restart 버튼을 통해 게임 재시작을 진행하는 기능

●UI 정보와 파라미터

이름 내용
GameoverUI 위치 게임 전체 화면
GameoverUI 크기 1280*720(게임 전체 화면 크기)
화면 활성화 초기값 false
GameoverUI 텍스트 위치 화면 정중앙
GameoverUI 텍스트 크기 60
GameoverUI 텍스트 색상 빨강
GameoverUI 텍스트 내용 YOU DIED
Restart 버튼 위치 GameoverUI Text 위치에서 GameoverUI Text 크기 만큼 한 칸 아래
Restart 버튼 외형 직사각형 버튼
Restart 버튼 크기 GameoverUI Text의 "YOU DIED" 크기와 동일한 폭과 너비
Restart 버튼 배경 색상 흰색
Restart 버튼 텍스트 크기 30
Restart 버튼 텍스트 색상 검정
Restart 버튼 텍스트 내용 Restart

●규칙

  • 레이어 출력 우선순위: 가장 높은 우선순위(모든 UI보다 상위에 출력한다)
  • GameoverUI 활성화 조건: 플레이어가 사망 시
  • GameoverUI 출력: 플레이어가 사망 시 GameoverUI를 활성화하여 GameoverUI Text와 Restart 버튼을 출력한다.
  • Restart 버튼: 버튼 터치 시 현재 게임을 초기화하고 재시작한다.

 

3.4.2.GameManager

  • 게임의 주요 규칙(Score 관리, 게임 오버 관리)을 관리하는 기능이다.
  • 게임 시작 시 플레이어의 사망 이벤트를 GameManager의 게임 오버 메소드가 구독하는 기능

3.4.2.1.Score 관리

  • 초기 점수 설정과 게임 플레이 시 획득 하는 점수를 관리하는 기능이다.

파라미터

파라미터 이름 데이터 타입 내용
score int -게임 플레이 시 플레이어가 획득한 현재 점수이다.
-점수는 양의 정수로 구성한다.
scoreDefault int -초기 점수: 0
newScore int -적 처치 시 획득한 점수

규칙

  • 초기 점수 설정: 게임 시작 시 초기 점수를 scoreDefault로 설정한다.
  • 점수 획득 규칙: 적 처치 시 획득한 newScore를 score에 합산한다.

 

3.4.2.2.Gameover관리

  • 플레이어가 사망 시 게임 오버를 적용하고 GameoverUI를 활성화하는 기능이다.

파라미터

파라미터 이름 데이터 타입 내용
isGameover boolean -플레이어가 사망 여부에 따라 게임 오버 상태인지 알려주는 파라미터이다.
-초기값: false

규칙

  • 플레이어 사망 이벤트 구독: 플레이어 사망 시 게임매니저에서 게임오버를 활성화하기 위해서 게임 시작 시 게임 매니저의 게임 오버 메소드가 플레이어의 사망 이벤트를 구독한다.
  • 게임 오버 적용
    -플레이어가 사망 시 isGameover를 true로 하여 게임 오버를 활성화한다.
    -UIManager에 접근하여 GameoverUI를 활성화한다.

 

 

3.4.3.EnemySpawner

  • 웨이브 시작 시 지정된 적 생성 위치에서 적들을 생성하는 기능이다.
  • 웨이브 마다 적의 능력치를 랜덤 설정(100~200%)하여 생성하는 기능이다.

 

적 생성 위치

  • 적 생성 위치는 최소 3개이다.
  • 적 생성 위치 개수는 밸런스 조절위해 개수 변경이 가능해야한다.
  • 적 생성 위치의 일정한 반경 안의 랜덤한 위치에 적을 생성한다.
  • 적 생성 위치는 마법진 모양의 오브젝트로 표시한다. 마법진 오브젝트를 통해 누군가 의해 소환되는 느낌을 보여주고 도시와 어울리지 않기 때문에 플레이어에게 수상한 위치라는 것을 직관적으로 알 수 있게 한다. 

 

적 생성 수 

첫 웨이브 적 생성 수 설정

  • 첫 웨이브 시작 시 적 타입 별 생성 개수를 설정할 수 있는 기능이다.
  • 첫 웨이브 적 생성 수
이름 enemyCount shamanCount ghostCount
개수 2 2 1

 

추가 적 생성 수 설정

  • 다음 웨이브가 진행될 때마다 이전 웨이브의 적 생성 개수에 추가하는 적 생성 개수를 설정하는 기능이다.
  • 추가 적 생성 수 설정
이름 addEnemyCount addShamanCount addGhostCount
개수 3 1 1

 

적 능력치 설정 파라미터

근접형 적 능력치 설정 파라미터

이름 내용
enemyMinHealth 근접형 적 최소 체력
enemyMaxHealth 근접형 적 최대 체력
enemyMinDamage 근접형 적 최소 공격력
enemyMaxDamage 근접형 적 최소 공격력
enemyMinSpeed 근접형 적 최소 이동속도
enemyMaxSpeed 근접형 적 최대 이동속도

 

원거리형 적 능력치 설정 파라미터

이름 내용
shamanMinHealth 원거리형 적 최소 체력
shamanMaxHealth 원거리형 적 최대 체력
shamanMinDamage 원거리형 적 최소 공격력
shamanMaxDamage 원거리형 적 최소 공격력
shamanMinRange 원거리형 적 최소 공격 사거리
shamanMaxRange 원거리형 적 최대 공격 사거리

#원거리형 적의 경우 이동 속도가 변경되서 빠르게 접근되는 것보다, 공격 사거리가 늘어나는 경우 플레이어 입장에서 까다로워지기 때문에 지루함 방지, 어려운 난이도를 위해서 이동 속도 대신 공격 사거리로 변경했다.

 

순간 이동형 적 능력치 설정 파라미터

이름 내용
ghostMinHealth 순간 이동형 적 최소 체력
ghostMaxHealth 순간 이동 적 최대 체력
ghostMinDamage 순간 이동 적 최소 공격력
ghostMaxDamage 순간 이동 적 최소 공격력

#순간 이동형 적의 경우 이동 속도가 빨라지면 순간 이동형 적의 순간이동 기술과 빠른 이동 속도 때문에
플레이어가 공격할 여유가 없어진다. 그래서 이동 속도 설정 파라미터는 제외했다.

 

●적 타입 별 획득 점수 파라미터

이름 데이터 타입 내용
enemyScore int 근접형 적 처치 시 획득 점수
shamanScore int 원거리형 적 처치 시 획득 점수
ghost int 순간 이동형 적 처치 시 획득 점수

 

●규칙

#규칙은 공통적인 부분을 일반규칙으로 뽑아내고 세부, 특별규칙을 따로 빼내라

 

1.웨이브 시작

  • 적 생성 위치마다 적 타입 별 생성 개수만큼 적을 생성한다.
  • 적 생성 개수
    -첫 웨이브일 때: 첫 웨이브 적 생성 개수만큼 적을 생성한다.
    -첫 웨이브 이후 일 때: '이전 웨이브 적 생성 개수' + '추가 적 생성 개수'만큼 추가하여 적을 생성한다.
  • 적 능력치 랜덤 설정
    -적을 생성할 때마다 적 능력치의 최소, 최대값을 100~200% 랜덤하게 능력치를 설정하여 생성한다.
  • 생성한 모든 적들의 수를 allEnemyCount에 저장한다.

2.웨이브 진행

  • 현재 웨이브의 모든 적이 처치됐을 경우(allEnemyCount = 0) 다음 웨이브를 진행한다.
  • 이전 웨이브 단계+1하여 새로운 웨이브를 시작한다.

3.웨이브 중지

  • 플레이어가 사망 시 웨이브 기능을 중지한다.

4.남은 적 수 관리

  • 현재 웨이브에서 생존한 적들 개수를 표시한다.
  • 적이 사망하면 allEnemyCount의 값을 1 감소한다.

5.적 처치

  • 플레이어에게 적이 처치되면 5초 뒤 오브젝트를 파괴한다.
  • 처치한 적의 점수를  GameManager에게 전달하여 newScore로 저장한다.

4.구현 과정

4.1.스크립트

UIManager 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; //재시작 시 씬 로드하려고
using UnityEngine.UI;

public class UIManager : MonoBehaviour
{
    //싱글턴 전용 프로퍼티
    public static UIManager instance
    {
        get
        {
            if(m_instance == null)
            {
                m_instance = FindObjectOfType<UIManager>();
            }

            return m_instance;
        }
    }

    //싱글턴이 할당될 변수
    private static UIManager m_instance;

    public Text scoreText; //점수 표시용 텍스트
    public Text waveText; //적 웨이브 표시용 텍스트
    public GameObject gameoverUI; //게임오버 시 활성화할 UI

    public void UpdateScoreText(int newScore)
    {
        scoreText.text = "Score : " + newScore;
    }

    public void UpdateWaveText(int waves, int count)
    {
        waveText.text = "Wave : "+waves + "\nEnemy Left : "+count;
    }

    public void GameRestart()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    public void SetActiveGameoverUI(bool active)
    {
        gameoverUI.SetActive(active);
    }
}

 

GameManager 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    //싱글턴 전용 프로퍼티
   public static GameManager instance
    {
        get
        {
           
            if(m_instance == null)
            {
                //씬에서 GameManager 오브젝트를 찾아서 할당
                m_instance = FindObjectOfType<GameManager>();
            }
            //싱글턴 오브젝트 반환
            return m_instance;
        }
    }

    //싱글턴이 할당될 static 변수
    private static GameManager m_instance;
    
    private int score = 0; //현재 게임 점수
    public bool isGameover { get; private set;}//게임 오버 상태

    private void Awake()
    {
        //씬에 싱글턴 오브젝트가 된 다른 GameManager 오브젝트가 있다면
        if(instance != this)
        {
            //자신을 파괴
            Destroy(gameObject);
        }
    }
    // Start is called before the first frame update
    void Start()
    {
        //플레이어 캐릭터의 사망 이벤트 발생 시 게임 오버
        FindObjectOfType<PlayerStats>().onDeath += EndGame;
        //PlayerStats의 onDeath 이벤트를 EnGame메서드가 구독 +=
    }

    //점수를 추가하고 UI 갱신
    public void AddScore(int newScore)
    {
        //게임 오버가 아닌 상태에서만 점수 추가 가능
        if (!isGameover)
        {
            //점수 추가
            score += newScore;
            //점수 UI 텍스트 갱신
            UIManager.instance.UpdateScoreText(score);
        }
    }

    //게임 오버 처리
    public void EndGame()
    {
        //게임 오버 상태를 참으로 변경
        isGameover = true;
        //게임 오버UI 활성화
        UIManager.instance.SetActiveGameoverUI(true);
    }
}

 

EnemySpawner 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    //적 프리팹
    public Enemy enemyPrefab;
    public EnemyShaman enemyShamanPrefab;
    public EnemyGhost enemyGhostPrefab;

    //적 스폰포인트
    public Transform[] enemySpawnPoints;

    //생성한 적을 담을 리스트
    private List<Enemy> enemies = new List<Enemy>();
    private List<EnemyShaman> enemyShamans = new List<EnemyShaman>();
    private List<EnemyGhost> enemyGhosts = new List<EnemyGhost>();

    private int allEnemyCount; //총 적 개수
    private int wave; //현재 웨이브

    //적 초기 개수
    public int defaultEnemyCount = 2;
    public int defaultEnemyShamanCount = 2;
    public int defaultEnemyGhostCount = 1;

    //적 생성 개수
    public int enemyCount;
    public int enemyShamanCount;
    public int enemyGhostCount;

    //적 추가 생성 개수
    public int addEnemyCount = 3;
    public int addShamanCount = 1;
    public int addGhostCount = 1;

    //근접 적 능력치 설정
    public float enemyMinHealth = 100;
    public float enemyMaxHealth = 150;
    public float enemyMinDamage = 20;
    public float enemyMaxDamage = 40;
    public float enemyMinSpeed = 3;
    public float enemyMaxSpeed = 5;

    //원거리 적 능력치 설정
    public float shamanMinHealth = 300;
    public float shamanMaxHealth = 600;
    public float shamanMinDamage = 30;
    public float shamanMaxDamage = 60;
    public float shamanMinRange = 10;
    public float shamanMaxRange = 15;

    //순간이동 적 능력치 설정
    public float ghostMinHealth = 200;
    public float ghostMaxHealth = 500;
    public float ghostMinDamage = 50;
    public float ghostMaxDamage = 100;
    //public float ghostMinSpeed = 4;
    //public float ghostMaxSpeed = 6;

    //적 점수
    public int enemyScore = 50;
    public int ghostScore = 100;
    public int shamanScore = 300; //샤먼이 더 까다롭고 잡기 힘드니까 높은 점수 주자


    private void Start()
    {
        enemyCount = defaultEnemyCount;
        enemyShamanCount = defaultEnemyShamanCount;
        enemyGhostCount = defaultEnemyGhostCount;
    }

    // Update is called once per frame
    void Update()
    {
     //게임 오버 상태일 때는 생성하지 않음
     if(GameManager.instance != null && GameManager.instance.isGameover)
        {
            return;
        }
     
     allEnemyCount = enemies.Count + enemyShamans.Count + enemyGhosts.Count;

     //적을 모두 처치 시 다음 웨이브 실행
        if (allEnemyCount <= 0)
        {
            SpawnWave();
        }

     //UI 갱신
     UpdateUI();

    }

    void UpdateUI()
    {
        //현재 웨이브와 남은 적 수 표시
        UIManager.instance.UpdateWaveText(wave, allEnemyCount);
    }

    //웨이브 설정
    void SpawnWave()
    {
        //웨이브 1증가
        wave++;

        if (wave > 1)
        {
            enemyCount += addEnemyCount;
            enemyShamanCount += addShamanCount;
            enemyGhostCount += addGhostCount;
        }

        //스폰 포인트 개수 만큼 실행
        for (int i = 0; i < enemySpawnPoints.Length; i++)
        {
            //스폰 포인트 위치 지정
            Transform spawnPoint = enemySpawnPoints[i];

            //적 생성 처리 실행
            CreateEnemy(spawnPoint);
            CreateShaman(spawnPoint);
            CreateGhost(spawnPoint);
        }

        //현재 웨이브 * 1.5를 반올림한 수만큼 적 생성
        //int spawnCount = Mathf.RoundToInt(wave * 1.5f);
    }

    //적 생성 위치 마다 적을 생성 적 능력치(근접형AI)
    void CreateEnemy(Transform spawnPoint)
    {
        //스폰 포인트 개수 만큼 실행
        for (int i = 0; i < enemyCount; i++)
        {
            //스폰 위치 랜덤 설정
            Vector3 randomSpawnPoint = spawnPoint.position + Random.insideUnitSphere * 2f;
            randomSpawnPoint.y = spawnPoint.position.y; //높이 초기화

            //적 능력치 랜덤 설정
            float intensity = Random.Range(0, 1f);

            //intensity를 기반으로 적의 능력치를 결정
            float health = Mathf.Lerp(enemyMinHealth, enemyMaxHealth, intensity); // 선형보간으로 특정 보정값일 떄의 최소~최대 체력 사이의 체력을 설정
            float damage = Mathf.Lerp(enemyMinDamage, enemyMaxDamage, intensity); // 선형보간으로 특정 보정값일 떄의 최소~최대 데미지 사이의 데미지를 설정
            float speed = Mathf.Lerp(enemyMinSpeed, enemyMaxSpeed, intensity); // 속도 설정

            //적 프리팹으로 적 생성
            Enemy enemy = Instantiate(enemyPrefab, randomSpawnPoint, spawnPoint.rotation);

            //생성한 적의 능력치와 추적 대상 설정
            enemy.Setup(health, damage, speed); //적 클래스로 접근해야 Setup 접근 가능

            //생성된 적을 리스트에 추가
            enemies.Add(enemy);

            //적의 onDeath 이벤트에 익명 메서드 등록
            //사망한 적을 리스트에 제거
            enemy.onDeath += () => enemies.Remove(enemy);
            //사망한 적을 5초 뒤에 파괴
            enemy.onDeath += () => Destroy(enemy.gameObject, 5f);
            //적 사망 시 점수 상승
            enemy.onDeath += () => GameManager.instance.AddScore(enemyScore);
        }
    }

    //원거리 적 생성
    void CreateShaman(Transform spawnPoint)
    {
        //스폰 포인트 개수 만큼 실행
        for (int i = 0; i < enemyShamanCount; i++)
        {
            //스폰 위치 랜덤 설정
            Vector3 randomSpawnPoint = spawnPoint.position + Random.insideUnitSphere * 2f;
            randomSpawnPoint.y = spawnPoint.position.y; //높이 초기화

            //적 능력치 랜덤 설정
            float intensity = Random.Range(0, 1f);

            //intensity를 기반으로 적의 능력치를 결정
            float health = Mathf.Lerp(shamanMinHealth, shamanMaxHealth, intensity); // 선형보간으로 특정 보정값일 떄의 최소~최대 체력 사이의 체력을 설정
            float damage = Mathf.Lerp(shamanMinDamage, shamanMaxDamage, intensity); // 선형보간으로 특정 보정값일 떄의 최소~최대 데미지 사이의 데미지를 설정
            float range = Mathf.Lerp(shamanMinRange, shamanMaxRange, intensity); // 속도 설정

            //적 프리팹으로 적 생성
            EnemyShaman shaman = Instantiate(enemyShamanPrefab, randomSpawnPoint, spawnPoint.rotation);

            //생성한 적의 능력치
            shaman.Setup(health, damage, range); //적 클래스로 접근해야 Setup 접근 가능

            //생성된 적을 리스트에 추가
            enemyShamans.Add(shaman);

            //적의 onDeath 이벤트에 익명 메서드 등록
            //사망한 적을 리스트에 제거
            shaman.onDeath += () => enemyShamans.Remove(shaman);
            //사망한 적을 5초 뒤에 파괴
            shaman.onDeath += () => Destroy(shaman.gameObject, 5f);
            //적 사망 시 점수 상승
            shaman.onDeath += () => GameManager.instance.AddScore(shamanScore);
        }
    }

    //순간이동 적 생성
    void CreateGhost(Transform spawnPoint)
    {
        //스폰 포인트 개수 만큼 실행
        for (int i = 0; i < enemyGhostCount; i++)
        {
            //스폰 위치 랜덤 설정
            Vector3 randomSpawnPoint = spawnPoint.position + Random.insideUnitSphere * 2f;
            randomSpawnPoint.y = spawnPoint.position.y; //높이 초기화

            //적 능력치 랜덤 설정
            float intensity = Random.Range(0, 1f);

            //intensity를 기반으로 적의 능력치를 결정
            float health = Mathf.Lerp(ghostMinHealth, ghostMaxHealth, intensity); // 선형보간으로 특정 보정값일 떄의 최소~최대 체력 사이의 체력을 설정
            float damage = Mathf.Lerp(ghostMinDamage, ghostMaxDamage, intensity); // 선형보간으로 특정 보정값일 떄의 최소~최대 데미지 사이의 데미지를 설정

            //적 프리팹으로 적 생성
            EnemyGhost ghost = Instantiate(enemyGhostPrefab, randomSpawnPoint, spawnPoint.rotation);


            ghost.Setup(health, damage); //적 클래스로 접근해야 Setup 접근 가능

            //생성된 적을 리스트에 추가
            enemyGhosts.Add(ghost);

            //적의 onDeath 이벤트에 익명 메서드 등록
            //사망한 적을 리스트에 제거
            ghost.onDeath += () => enemyGhosts.Remove(ghost);
            //사망한 적을 5초 뒤에 파괴
            ghost.onDeath += () => Destroy(ghost.gameObject, 5f);
            //적 사망 시 점수 상승
            ghost.onDeath += () => GameManager.instance.AddScore(ghostScore);
        }
    }


}

 

4.2.UIManager

1.HUD Canvas에 ScoreUI, WaveUI, GameoverUI를 생성한다. GameoverUI를 비활성화한다.
 -ScoreUI, WaveUI: HUD Canvas > 우클릭 > UI > Text를 추가 > Text 컴포넌트에서 내용, 크기, 정렬 방법, 색상 설정
 -GameoverUI: HUD Canvas > 우클릭 > UI > Image를 추가, Text 추가 > Image 색상을 변경, Text 적기
 -Restart 버튼: GameoverUI > 우클릭 > UI > Button를 추가 > Button에 Text 추가 > Button 컴포넌트의 On Click > UIManager의 GameRestart() 연결

 

2.GameoverUI는 가장 아래에 위치한다.(가장 아래에 있어야 다른 UI보다 위에 출력된다.)

 

3.게임 화면에 출력하는 UI를 관리해야 하기 때문에 HUD Canvas에 UIManager 스크립트를 할당한다.

4.UIManager스크립트에 ScoreUI, WaveUI, GameoverUI를 할당한다.

 

4.2.GameManager

1. 하이어라키 > 빈 게임 오브젝트 생성 > 이름을 GameManager으로 변경 > GameManager 스크립트 추가

 

4.3.EnemySpawner

1.하이어라키 > 빈 게임 오브젝트 생성 > 이름을 EnemySpawner로 변경 > EnemySpawner 스크립트 추가

2.EnemySpawner의 생성할 적 타입 별 프리팹 추가

3.테스트 플레이 후 적 능력치, 점수, 생성 개수 등 밸런스 조절하기

반응형

댓글