[Unity]12.좀비 서바이버 따라하기 #6 - 게임 매니저와 포스트 프로세싱
- 게임 개발 - Unity3d
- 2019. 9. 15. 10:54
안녕하세요 유랑입니다.
실력향상을 위해서 오늘도 책을 따라하면서 공부하겠습니다.
궁금하신점 있으시면 댓글로 남겨주세요^^
1. 좀비 서바이버
이번 강의는 레트로님께서 만든 예제이며,
교재를 구입하시면 자세한 내용을 배우실 수 있습니다.
저는 책을 구입하였고, 스킬업을 위해서 복습겸 글을 올리겠습니다.
깃허브 사이트 => 깃허브
유튜브 사이트 => 유튜브
1-1) UI 다루기 - ㉠HUD Canvas
어느덧 좀비 서바이버 따라하기 마무리 단계입니다.
점수와 탄알, 게임에 관련된 UI를 추가하겠습니다.
HUD Canvas를 추가해 주세요.
HUD Canvas는 자식으로 다음과 같은 UI 오브젝트를 가집니다.
* Ammo Display : 남은 탄알을 표시하는 창
* Ammo Text : 탄알을 표시하는 텍스트
* Score Text : 점수를 표시하는 텍스트
* Enemy Wave Text : 현재 적 웨이브와 남은 적 수를 표시하는 텍스트
* Gameover UI : 게임오버 시 활성화되는 패널
* Gameover Text : 게임오버 안내 텍스트
* Restart Button : 게임 재시작 버튼
* Text : 버튼의 텍스트
해상도는 1280 x 720으로 설정합니다.
16:9 비율의 화면에 최적화 시켰습니다.
1-2) UI 다루기 - ㉡UIManager 스크립트
<UIManager>
UI 관련 구현을 모아두는 스크립트입니다.
탄알, 점수, 적 웨이브 등의 정보를 가지고 있어요ㅎㅎ
using UnityEngine; using UnityEngine.SceneManagement; // 씬 관리자 관련 코드 using UnityEngine.UI; // UI 관련 코드 // 필요한 UI에 즉시 접근하고 변경할 수 있도록 허용하는 UI 매니저 public class UIManager : MonoBehaviour { // 싱글톤 접근용 프로퍼티 public static UIManager instance { get { if (m_instance == null) { m_instance = FindObjectOfType(); } return m_instance; } } private static UIManager m_instance; // 싱글톤이 할당될 변수 public Text ammoText; // 탄약 표시용 텍스트 public Text scoreText; // 점수 표시용 텍스트 public Text waveText; // 적 웨이브 표시용 텍스트 public GameObject gameoverUI; // 게임 오버시 활성화할 UI // 탄약 텍스트 갱신 public void UpdateAmmoText(int magAmmo, int remainAmmo) { ammoText.text = magAmmo + "/" + remainAmmo; } // 점수 텍스트 갱신 public void UpdateScoreText(int newScore) { scoreText.text = "Score : " + newScore; } // 적 웨이브 텍스트 갱신 public void UpdateWaveText(int waves, int count) { waveText.text = "Wave : " + waves + "\nEnemy Left : " + count; } // 게임 오버 UI 활성화 public void SetActiveGameoverUI(bool active) { gameoverUI.SetActive(active); } // 게임 재시작 public void GameRestart() { SceneManager.LoadScene(SceneManager.GetActiveScene().name); } }
스크립트 적용이 끝나셨으면 텍스트랑 UI가 잘 연결되어있는지 확인해 주세요^^
이미 적용되어 있을거에요.
1-3) UI 다루기 - ㉢재시작 버튼 설정
재시작 버튼을 클릭하였을 때 HUD Canvas스크립트의 재시작 기능을 사용하도록
연결시켜 주겠습니다.
On Click () 리스트의 + 버튼을 클릭한 후 HUD Canvas를 드래그하고
UIManager.GameRestart 기능으로 설정해 주세요!!
Gameover UI는 캐릭터 사망시 활성화 되므로,
활성화 체크를 해제해 주겠습니다.
1-4) 게임 매니저
게임의 전반적인 규칙을 관리하는 게임 매니저를 만들어 보겠습니다.
빈 오브젝트 생성 후 이름을 Game Manger로 바꾸고 스크립트를 연결해 주세요.
<GameManger>
GameManger 스크립트는 점수 관리, 게임오버 상태 관리, 게임오버 UI 갱신 등을 관리합니다^^
using UnityEngine; // 점수와 게임 오버 여부를 관리하는 게임 매니저 public class GameManager : MonoBehaviour { // 싱글톤 접근용 프로퍼티 public static GameManager instance { get { // 만약 싱글톤 변수에 아직 오브젝트가 할당되지 않았다면 if (m_instance == null) { // 씬에서 GameManager 오브젝트를 찾아 할당 m_instance = FindObjectOfType(); } // 싱글톤 오브젝트를 반환 return m_instance; } } private static GameManager m_instance; // 싱글톤이 할당될 static 변수 private int score = 0; // 현재 게임 점수 public bool isGameover { get; private set; } // 게임 오버 상태 private void Awake() { // 씬에 싱글톤 오브젝트가 된 다른 GameManager 오브젝트가 있다면 if (instance != this) { // 자신을 파괴 Destroy(gameObject); } } private void Start() { // 플레이어 캐릭터의 사망 이벤트 발생시 게임 오버 FindObjectOfType ().onDeath += EndGame; } // 점수를 추가하고 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); } }
1-5) 적 생성기 - ㉠생성 위치 추가
적을 실시간으로 생성해 줄 적 생성기를 만들어 보겠습니다.
우선 Spawn Points를 추가해 주세요.
적이 생성될 위치의 정보를 담고있습니다.
1-6) 적 생성기 - ㉡Enemy Spawner 스크립트
빈 오브젝트를 생성 후 Enemy Spawner라고 이름을 변경과 함께 스크립트를 추가해 주세요.
<EnemySpawner>
EnemySpawner 스크립트는 해당 웨이브에 적을 생성하도록 합니다.
적을 생성할 위치는 Spawn Points를 참고 합니다.
using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; // 적 게임 오브젝트를 주기적으로 생성 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 Listenemies = new List (); // 생성된 적들을 담는 리스트 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에 반올림 한 개수 만큼 적을 생성 int spawnCount = Mathf.RoundToInt(wave * 1.5f); // spawnCount 만큼 적을 생성 for (int i = 0; i < spawnCount; i++) { // 적의 세기를 0%에서 100% 사이에서 랜덤 결정 float enemyIntensity = Random.Range(0f, 1f); // 적 생성 처리 실행 CreateEnemy(enemyIntensity); } } // 적을 생성하고 생성한 적에게 추적할 대상을 할당 private void CreateEnemy(float intensity) { // intensity를 기반으로 적의 능력치 결정 float health = Mathf.Lerp(healthMin, healthMax, intensity); float damage = Mathf.Lerp(damageMin, damageMax, intensity); float speed = Mathf.Lerp(speedMin, speedMax, intensity); // intensity를 기반으로 하얀색과 enemyStrength 사이에서 적의 피부색 결정 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); // 적의 onDeath 이벤트에 익명 메서드 등록 // 사망한 적을 리스트에서 제거 enemy.onDeath += () => enemies.Remove(enemy); // 사망한 적을 10 초 뒤에 파괴 enemy.onDeath += () => Destroy(enemy.gameObject, 10f); // 적 사망시 점수 상승 enemy.onDeath += () => GameManager.instance.AddScore(100); } }
스크립트 적용이 끝났으면 좀비 프리팹과 적 생성 위치를 넣어주세요^^
이렇게 적이 몰려드니 무섭네요ㅎㄷㄷ
1-7) 아이템 생성기
난이도가 어렵다구요?
그러면 아이템을 이용해 쉽게 가보도록 하시죠.
빈 오브젝트를 생성 후 이름을 Item Spawner로 변경과 함께 스크립트를 적용해 주세요.
<ItemSpawner>
ItemSpawner 스크립트는 주기적으로 아이템 생성,
내비메시 위에서 랜덤한 한 점을 선택하여 아이템 생성 위치로 사용합니다.
using UnityEngine; using UnityEngine.AI; // 내비메쉬 관련 코드 // 주기적으로 아이템을 플레이어 근처에 생성하는 스크립트 public class ItemSpawner : MonoBehaviour { public GameObject[] items; // 생성할 아이템들 public Transform playerTransform; // 플레이어의 트랜스폼 public float maxDistance = 5f; // 플레이어 위치로부터 아이템이 배치될 최대 반경 public float timeBetSpawnMax = 7f; // 최대 시간 간격 public float timeBetSpawnMin = 2f; // 최소 시간 간격 private float timeBetSpawn; // 생성 간격 private float lastSpawnTime; // 마지막 생성 시점 private void Start() { // 생성 간격과 마지막 생성 시점 초기화 timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax); lastSpawnTime = 0; } // 주기적으로 아이템 생성 처리 실행 private void Update() { // 현재 시점이 마지막 생성 시점에서 생성 주기 이상 지남 // && 플레이어 캐릭터가 존재함 if (Time.time >= lastSpawnTime + timeBetSpawn && playerTransform != null) { // 마지막 생성 시간 갱신 lastSpawnTime = Time.time; // 생성 주기를 랜덤으로 변경 timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax); // 아이템 생성 실행 Spawn(); } } // 실제 아이템 생성 처리 private void Spawn() { // 플레이어 근처에서 내비메시 위의 랜덤 위치 가져오기 Vector3 spawnPosition = GetRandomPointOnNavMesh(playerTransform.position, maxDistance); // 바닥에서 0.5만큼 위로 올리기 spawnPosition += Vector3.up * 0.5f; // 아이템 중 하나를 무작위로 골라 랜덤 위치에 생성 GameObject selectedItem = items[Random.Range(0, items.Length)]; GameObject item = Instantiate(selectedItem, spawnPosition, Quaternion.identity); // 생성된 아이템을 5초 뒤에 파괴 Destroy(item, 5f); } // 내비메시 위의 랜덤한 위치를 반환하는 메서드 // center를 중심으로 distance 반경 안에서 랜덤한 위치를 찾는다 private Vector3 GetRandomPointOnNavMesh(Vector3 center, float distance) { // center를 중심으로 반지름이 maxDistance인 구 안에서의 랜덤한 위치 하나를 저장 // Random.insideUnitSphere는 반지름이 1인 구 안에서의 랜덤한 한 점을 반환하는 프로퍼티 Vector3 randomPos = Random.insideUnitSphere * distance + center; // 내비메시 샘플링의 결과 정보를 저장하는 변수 NavMeshHit hit; // maxDistance 반경 안에서, randomPos에 가장 가까운 내비메시 위의 한 점을 찾음 NavMesh.SamplePosition(randomPos, out hit, distance, NavMesh.AllAreas); // 찾은 점 반환 return hit.position; } }
스크립트 적용이 끝나셨으면 아이템들을 넣어주세요.
아이템 마다 콜라이더, 라이드, 해당 스크립트로 이루어져 있습니다.
아이템 먹고 점수를 높이자구요ㅎㅎ
1-8) 포스트 프로세싱 - ㉠포스트 프로세싱 스택
게임 구성은 거의 끝났습니다.
포스트 프로세싱을 이용해 뛰어난 영상미를 보여줄 차례입니다.
포스트 프로세싱은 카메라 앱의 필터와 비슷하다고 보시면 됩니다.
1-9) 포스트 프로세싱 - ㉡카메라 렌더 설정
포스트 프로세싱을 적용하기 전에 카메라의 렌더 설정을 디퍼트 셰이딩으로 변경하겠습니다.
최상의 품질을 얻기 위해서는 꼭 필요하다고 하네요.
* 포워드 렌더링 : 성능이 가볍지만 라이팅 표현이 실제보다 간략화되고 왜곡됩니다.
* 디퍼트 셰이딩 : 라이팅 연산을 마뤄서 실행하는 방식. 개수 제한 없이 광원 표현이 가능.
(MSAA 지원 X)
1-10) 포스트 프로세싱 - ㉢포스트 프로세스 레이어
이제 포스트 프로세싱을 적용하겠습니다.
카메라에 포스트 프로세스 레이어 컴포넌트를 적용해 주세요.
포스트 프로세스 레이어는 포스트 프로세싱 볼륨을 감지하고
포스트 프로세싱 볼륨으로부터 설정을 얻어와 카메라에 적용됩니다.
이 때 특정 레이어만 감지하도록 레이어 설정을 해주겠습니다.
* FXAA : 전반적인 품질은 높지 않지만 성능 저하가 가장 적고 연산이 빠른 방식
1-11) 포스트 프로세싱 - ㉣포스트 프로세스 볼륨
마지막으로 포스트 프로세스 볼륨을 추가해 주겠습니다.
Create => 3D Object => Post-process Volume을 클릭해 생성해 주세요.
포스트 프로세스 볼륨은 트리거 콜라이더와 함께 사용합니다.
Is Global을 체크하면 카메라의 위치와 상관없이 효과를 전역으로 사용가능 합니다.
레이어도 꼭 설정해 주세요.
포스트 프로세스 프로파일은 사용할 효과 목록을 기록하는 파일입니다.
New 버튼을 클릭해 새로운 파일 생성이 가능하지만,
저는 예제에 있는 걸로 적용하였습니다.
기존 목록에 다른 효과도 적용 가능하답니다^^
* 모션 블러 : 빠르게 움직이는 물체에 대한 잔상
* 블룸 : 밝은 물체의 경계에서 빛이 산란되는 효과(뽀샤시)
* 컬러 그레이딩 : 최정 컬러, 대비, 감마 등을 조정(사진 필터)
* 색 수차 : 이미지의 경계가 번지고 삼원색이 분리되는 효과(방사능 중독 효과)
* 비네트 : 화면 가장자리의 채도와 명도를 낮추는 효과
* 그레인 : 화면에 입자 노이즈 추가
1-12) 마무리 - ㉠배경음 추가
마무리 단계입니다.
배경음악 추가 후 빌드를 진행하겠습니다.
게임 매니저 오브젝트에 오디오 소스 컴포넌트 추가 후 오디오 클립을 적용해 주세요.
Loop를 체크해주면 무한으로 음악이 실행됩니다.
1-13) 마무리 - ㉡빌드하기
상단 메뉴 File => Build Settings를 클릭하면 빌드 창이 보입니다.
현재 씬을 빌드 목록에 등록한 후 Build and Run을 클릭하여 빌드를 진행해 주세요.
우와 드디어 게임을 완성했네요.
물론 책의 내용을 따라한거지만,
여기까지 한 것도 대단합니다!!
2. 마무리
오늘 강의는 여기까지입니다.
좀비 서바이버를 따라하면서 게임 매니저와 포스트 프로세싱을 만들어 보았습니다.
책이랑 순서나 내용이 다를 수 있습니다.
감사합니다.
수업자료: 좀비 서바이버 따라하기 #6 - 게임 매니저와 포스트 프로세싱