13. 들어가기 전에
이 장에서는 발판을 만들고, 발판을 반복 생성하는 발판 생성기를 만든다. 그리고 게임을 완성하고 빌드한다.
시작 지점의 발판과 달리 일반 발판은 밟는 순간 점수가 증가한다. 일반 발판 위에는 장애물이 랜덤 생성된다. 발판을 만들고 나면 발판 생성기를 만든다. 발판 생성기는 발판을 매번 새로 생성하는 대신 미리 만들어진 발판 게임 오브젝트를 재활용하는 방식으로 메모리를 아낀다.
레트로의 유니티 게임 프로그래밍 에센스 | 이제민 - 교보문고
레트로의 유니티 게임 프로그래밍 에센스 | 이제민 - 교보문고
레트로의 유니티 게임 프로그래밍 에센스 | 독자분들로부터 수많은 찬사를 받았던 유니티 대표 도서 『소문난 명강의:레트로의 유니티 게임 프로그래밍 에센스』가 개정판으로 돌아왔습니다!
product.kyobobook.co.kr
13.1 발판 만들기
현재 씬에는 시작 지점의 발판인 Start Platform 게임 오브젝트만 있다. 해당 게임 오브젝트에는 별다른 기능이 없다. 하지만 시작 지점 이후의 일반 발판은 플레이어 캐릭터가 밟을 경우 점수가 올라가는 기능과 발판 위에 장애물을 생성하는 기능을 갖는다.
발판 위에 장애물을 배치하는 시간을 아끼기 위해 발판의 초안은 저자가 프리팹으로 미리 만들었다. 발판 프리팹을 씬에 추가한다.
1. Platform 프리팹 배치하기(1)
- Prefabs 폴더에서 Platform 프리팹을 하이어라키 창으로 드래그&드롭
- 생성된 게임 오브젝트의 Sprite Renderer 컴포넌트의 Sorting Layer 를 Foreground 로 변경

2. Platform 프리팹 배치하기(2)
- Platform 게임 오브젝트의 자식들(Obstacle Left, Obstacle Mid, Obstacle Right) 을 Shift+클릭 으로 모두 선택
- 자식들의 Sprite Renderer 컴포넌트의 Sorting Layer 를 Middleground 로 변경

Platform 프리팹으로부터 생성한 Platform 게임 오브젝트는 박스 콜라이더 2D, 스프라이트 렌더러, Scrolling Object 스크립트를 가지고 있다. 자식으로는 장애물 게임 오브젝트를 3개(Obstacle Right, Mid, Left) 가지고 있다.
장애물 게임 오브젝트는 배경보다는 앞에, 플레이어 캐릭터와 발판보다는 뒤에 그려지도록 정렬 레이어를 Middleground 로 변경했다.
장애물 게임 오브젝트는 모두 트리거로 설정된 박스 콜라이더 2D 를 가지고 있고, Dead 태그를 가지고 있다. 따라서 플레이어 캐릭터는 발판 위의 장애물에 닿는 즉시 사망한다.
13.1.1 Platform 스크립트
발판은 플레이어 캐릭터가 자신을 밟으면 게임 점수를 증가시켜야 한다. 또한 자신의 장애물 게임 오브젝트를 일정한 확률로 활성화해야 한다.
1. Platform 스크립트 적용하기
- Scripts 폴더에서 Platform 스크립트를 하이어라키 창의 Platform 게이미 오브젝트로 드래그&드롭
- Platform 스크립트를 더블 클릭으로 열기

스크립트를 열면 보이는 변수이다. obstacles 는 Platform 게임 오브젝트의 자식으로 있는 장애물 게임 오브젝트를 할당할 변수이다. 여러 장애물 게임 오브젝트를 한 번에 다룰 수 있도록 배열 타입으로 선언했다.
stepped 는 플레이어 캐릭터가 자신을 이미 밟았는지 알려주는 상태 변수이다. stepped 의 초깃값은 false 이다. 플레이어가 발판을 밟으면 stepped 는 true 가 된다.
stepped 를 사용해 발판을 중복해서 밟았을 때 점수가 반복 상승되는 것을 막을 수 있다.
public GameObject[] obstacles; // 장애물 오브젝트들
private bool stepped = false; // 플레이어 캐릭터가 밟았었는가
13.1.2 Platform 의 OnEnable() 메서드
OnEnable() 메서드는 Awake() 나 Start() 같은 유니티 이벤트 메서드이다. Start() 메서드처럼 컴포넌트가 활성화될 때 자동으로 한 번 실행된다. 하지만 처음 한 번만 실행되는 Start() 메서드와 달리 OnEnable() 메서드는 컴포넌트가 활성화될 때마다 매번 다시 실행된다. 따라서 OnEnable() 메서드는 컴포넌트를 끄고 다시 켜는 방식으로 재실행할 수 있다.
게임 오브젝트가 활성화/비활성화되면 게임 오브젝트의 모든 컴포넌트도 함께 활성화/비활성화된다. 따라서 개별 컴포넌트를 끄고 켜지 않고 게임 오브젝트를 끄고 켜는 방식으로 컴포넌트의 OnEnable() 메서드를 재실행하는 것도 가능하다.
OnEnable() 메서드는 게임 오브젝트가 활성화될 때마다 상태를 리셋하는 기능을 구현할 때 주로 이용된다. OnEnable() 에 초기화 코드를 넣어두고, 게임 오브젝트의 정보를 리셋해야 할 때마다 게임 오브젝트를 끄고 다시 켜는 방식으로 활용한다.
우리는 OnEnable() 메서드에 발판을 리셋하는 코드를 넣는다. 그리고 리셋이 필요할 때마다 발판 게임 오브젝트를 끄고 다시 켤 것이다.
1. Platform 스크립트의 OnEnable() 완성하기
Platform 게임 오브젝트는 자식 오브젝트로 세 개의 장애물을 가지고 있다. obstacles 에는 세 개의 장애물이 들어가 있으므로 for 문을 돌면서 1/3 확률로 장애물을 활성화 하도록 했다.
Random.Range(0, 3) 은 0, 1, 2 중에서 한 숫자를 랜덤으로 반환한다. 즉, Random.Range(0, 3) 의 반환값이 0일 확률은 1/3 이다.
이것으로 발판을 리셋하는 메서드를 완성했다. 이제 발판 게임 오브젝트가 비활성화된 후 다시 활성화될 때마다 밟힘 상태가 리셋되고 활성화될 장애물 수가 랜덤하게 변경될 것이다.
// 컴포넌트가 활성화될때 마다 매번 실행되는 메서드
private void OnEnable() {
// 발판을 리셋하는 처리
// 밟힘 상태를 리셋
stepped = false;
// 장애물의 수만큼 루프
for (int i=0; i<obstacles.Length; i++)
{
// 현재 순번의 장애물을 1/3의 확률로 활성화
if (Random.Range(0, 3) == 0)
{
obstacles[i].SetActive(true);
}
else
{
obstacles[i].SetActive(false);
}
}
}
13.1.3 Platform 의 OnCollisionEnter2D() 메서드
플레이어 캐릭터가 새로운 발판을 밟을 때마다 점수가 상승한다. 플레이어 캐릭터가 가진 2D 콜라이더와 발판의 2D 콜라이더 간의 충돌은 OnCollisionEnter2D() 메서드로 감지할 수 있다.
OnCollisionEnter2D() 메서드에 플레이어 캐릭터를 감지하고 점수를 추가하는 코드를 작성해본다.
1. Platform 스크립트의 OnCollisionEnter2D() 메서드 완성하기
!stepped 가 참인지 검사하기 때문에 플레이어 캐릭터가 같은 발판을 두 번 이상 밟았을 때 점수가 중복 상승하는 상황이 발생하지 않는다.
void OnCollisionEnter2D(Collision2D collision) {
// 플레이어 캐릭터가 자신을 밟았을때 점수를 추가하는 처리
// 충돌한 상대방의 태그가 Player 이고 이전에 플레이어 캐릭터가 밟지 않았다면
if (collision.collider.tag == "Player" && !stepped)
{
// 점수를 추가하고 밟힘 상태를 참으로 변경
stepped = true;
GameManager.instance.AddScore(1);
}
}
13.1.4 Platform 스크립트 전체 코드
using UnityEngine;
// 발판으로서 필요한 동작을 담은 스크립트
public class Platform : MonoBehaviour {
public GameObject[] obstacles; // 장애물 오브젝트들
private bool stepped = false; // 플레이어 캐릭터가 밟았었는가
// 컴포넌트가 활성화될때 마다 매번 실행되는 메서드
private void OnEnable() {
// 발판을 리셋하는 처리
// 밟힘 상태를 리셋
stepped = false;
// 장애물의 수만큼 루프
for (int i=0; i<obstacles.Length; i++)
{
// 현재 순번의 장애물을 1/3의 확률로 활성화
if (Random.Range(0, 3) == 0)
{
obstacles[i].SetActive(true);
}
else
{
obstacles[i].SetActive(false);
}
}
}
void OnCollisionEnter2D(Collision2D collision) {
// 플레이어 캐릭터가 자신을 밟았을때 점수를 추가하는 처리
// 충돌한 상대방의 태그가 Player 이고 이전에 플레이어 캐릭터가 밟지 않았다면
if (collision.collider.tag == "Player" && !stepped)
{
// 점수를 추가하고 밟힘 상태를 참으로 변경
stepped = true;
GameManager.instance.AddScore(1);
}
}
}
13.1.5 Platform 컴포넌트 설정하기
1. Platform 컴포넌트 설정하기
- 하이어라키 창에서 Platform 게임 오브젝트 선택
- Platform 컴포넌트의 Obstacles 의 배열 크기를 3으로 변경 > Obstacles 필드 펼치기
- Obstacles 에 Obstacle Left, Obstacle Mid, Obstacle Right 할당

2. Platform 프리팹 갱신하기
- 하이어라키 창에서 Platform 게임 오브젝트 선택
- 인스펙터 창에서 Overrides > Apply All 클릭
- Platform 게임 오브젝트 삭제(하이어라키 창에서 Platform 에 마우스 오른쪽 클릭 > Delete)


13.2 발판 생성기 만들기
발판 프리팹으로 발판을 무한 반복 생성해서 배치하는 발판 생성기를 구현한다.
무한 반복 생성되는 발판을 구현하는 가장 간단한 방법은 필요할 때마다 매번 새로운 발판을 생성하는 것이다. 하지만 발판 오브젝트 수가 계속 늘어나기 때문에 메모리 사용량이 계속 증가한다. 또한 새로운 발판을 생성할 때마다 처리량이 늘어나 게임이 끊길 수 있다.
이러한 문제를 해결하기 위해 발판을 오브젝트 풀링 방식으로 생성하고 관리한다.
13.2.1 오브젝트 풀링
오브젝트 풀링이란 초기에 필요한 만큼 오브젝트를 미리 만들어 풀에 쌓아두는 방식이다.
풀에 오브젝트를 생성해둔 이후에는 새로운 오브젝트가 필요할 때 새로운 오브젝트를 생성하지 않고 풀에 있는 오브젝트를 가져다 쓴다. 오브젝트가 필요 없을 때는 파괴하는 대신 오브젝트를 비활성화하고 풀에 반환한다.
Instantiate() 메서드처럼 오브젝트를 실시간으로 생성하거나, Destroy() 메서드처럼 오브젝트를 실시간으로 파괴하는 처리는 성능을 많이 요구한다. 또한 메모리를 정리하는 GC(가비지 컬렉션) 을 유발하기 쉽다. 따라서 게임 도중에 오브젝트를 너무 자주 생성하거나 파괴하면 게임 끊김(프리즈) 현상을 겪게 된다.
오브젝트 풀링을 사용하면 생성할 오브젝트를 생성하지 않고 풀에서 가져다 쓰고, 파괴할 오브젝트를 파괴하지 않고 풀에 반납한다. 그리고 풀에 반납한 오브젝트는 나중에 다시 꺼내 재사용할 수 있다. 따라서 오브젝트 풀링을 사용하면 게임 끊김 현상이 현저하게 줄어든다.
13.2.2 발판 무한 배치 과정
오브젝트 풀링의 개념을 사용해 미리 생성한 3개의 발판을 재사용하여 끊임없이 발판이 생성되는 것처럼 보이게 한다.
1. 발판 풀 생성
- 3개의 발판 오브젝트를 미리 만들어 풀에 배치
게임이 시작되면 필요한 만큼 발판 오브젝트를 생성하여 게임 화면에 보이지 않는 구석진 장소에 배치ㅣ한다. 생성된 발판들은 각자 가지고 있는 ScrollingObject 컴포넌트에 의해 항상 왼쪽으로 이동한다.
그다음 게임이 시작되고 일정 시간이 지나면 순서대로 발판 배치를 시작한다.

2. 첫 번째 배치 루프
- 일정 시간 후 1번 발판을 리셋하고 화면 오른쪽에 재배치
- 일정 시간 후 다음(1번 -> 2번) 발판을 리셋하고 화면 오른쪽에 재배치
- 일정 시간 후 다음(2번 -> 3번) 발판을 리셋하고 화면 오른쪽에 재배치

생성된 발판은 순서대로 일정 간격을 두고 게임 화면 오른쪽에 배치된다. 발판은 재배치되기 전에 상태를 리셋하는 과정을 거친다.
그런데 과정 2의 3번에서 발판 3까지 배치하면 다음 순번에 배치할 발판이 없다. 여기서 발판 3이 배치될 때 발판 1은 이미 게임 화면을 벗어난 상태라는 점에 주목핳ㄴ다.
발판 1은 이미 게임 화면을 벗어났기 때문에 어떠한 쓸모도 없다. 따라서 쓸모없게 된 발판 1을 리셋하여 발판 3의 다음 순번으로 사용한다.
이렇게 게임 화면을 벗어난 발판을 다시 사용하는 방식으로 3개의 발판만 가지고 발판을 무한 생성하는 것처럼 만들 수 있다.
3. 첫 번째 이후 배치 루프
- 일정 시간 후(3번 -> 1번) 발판을 리셋하고 화면 오른쪽에 재배치
- 일정 시간 후(1번 -> 2번) 발판을 리셋하고 화면 오른쪽에 재배치
- 일정 시간 후(2번 -> 3번) 발판을 리셋하고 화면 오른쪽에 재배치
- ... 반복

13.2.3 PlaformSpawner 스크립트 작성하기
앞에서 다룬 원리를 이용해 발판을 생성하고 주기적으로 재배치하는 PlatformSpawner 스크립트를 게임 오브젝트에 추가하고 스크립트를 완성한다.
1. PlatformSpawner 스크립트 열기
- 빈 게임 오브젝트 생성(하이어라키 창에서 + > Create Empty)
- 생성된 게임 오브젝트의 이름을 Platform Spawner 로 변경
- Scripts 폴더의 PlatformSpawner 스크립트를 하이어라키 창의 Platform Spawner 게임 오브젝트로 드래그&드롭
- PlatformSpawner 스크립트를 더블 클릭하여 열기

13.2.4 PlatformSpawner 의 필드
PlatformSpawner 스크립트에서 변수를 선언한 부분(필드) 을 먼저 살펴본다.
platformPrefab 에는 복제 생성할 발판 게임 오브젝트의 원본 프리팹이 할당된다. count 는 복제 생성할 발판 수를 결정한다. 만약 발판 3개가 돌아가며 사용하기에 충분하지 않다면 count 값을 늘려도 된다.
public GameObject platformPrefab; // 생성할 발판의 원본 프리팹
public int count = 3; // 생성할 발판의 개수
그 아래에는 생성 주기와 관련된 변수가 선언되어 있다.
timeBetSpawn 은 현재 순번의 발판이 배치된 후 다음번 발판을 배치할 때까지 소요되는 시간이다. 우리는 timeBetSpawn 의 값을 배치할 때마다 매번 랜덤하게 변경할 것이다. 그러면 게임이 더 여렵고 재미있게 느껴진다.
timeBetSpawn 위에 선언된 timeBetSpawnMin, timeBetSpawnMax 는 timeBetSpawn 의 최솟값과 최댓값을 결정한다.
public float timeBetSpawnMin = 1.25f; // 다음 배치까지의 시간 간격 최솟값
public float timeBetSpawnMax = 2.25f; // 다음 배치까지의 시간 간격 최댓값
private float timeBetSpawn; // 다음 배치까지의 시간 간격
그다음 발판을 재배치할 위치를 결정하는 변수들이 선언되어 있다.
xPos 는 발판을 배치할 X 축 위치이다. 발판을 배치할 가로 방향 X축 위치는 항상 게임 화면 오른쪽 20으로 고정이다.
높이(Y축) 는 yMin 과 yMax 사이에서 랜덤 결정한다. 그러면 매번 배치되는 발판의 높이가 달라져 게임이 재미있게 느껴진다.
public float yMin = -3.5f; // 배치할 위치의 최소 y값
public float yMax = 1.5f; // 배치할 위치의 최대 y값
private float xPos = 20f; // 배치할 위치의 x 값
그다음 생성한 발판 게임 오브젝트를 저장할 배열과 배열에 할당된 발판 중 현재 사용할 발판의 순번을 가리킬 변수가 선언되어 있다.
platforms 는 프리팹으로부터 생성한 발판 게임 오브젝트를 저장할 배열 변수이고, currentIndex 는 platforms 에 할당된 발판 중에서 지금 사용할 발판을 가리키는 순번이다.
private GameObject[] platforms; // 미리 생성한 발판들
private int currentIndex = 0; // 사용할 현재 순번의 발판
마지막으로 발판 게임 오브젝트를 초반에 모아둘 장소와 마지막으로 재배치를 실행한 시점을 저장하는 변수가 선언되어 있다.
poolPosition 은 게임 시작 시 생성한 발판 게임 오브젝트를 배치할 곳이다. 생성한 발판 게임 오브젝트는 초반에는 게임 화면에 보여선 안 되기 때문에 위치값을 (0, -25) 로 할당했다.
lastSpawnTime 은 가장 최근에 발판을 재배치한 시점이다. 발판을 재배치할 때마다 매번 갱신되며, 발판을 언제 재배치해야 하는지 계산할 때 사용한다.
private Vector2 poolPosition = new Vector2(0, -25); // 초반에 생성된 발판들을 화면 밖에 숨겨둘 위치
private float lastSpawnTime; // 마지막 배치 시점
13.2.5 PlatformSpawner 의 Start() 메서드
Start() 메서드에서는 상태를 표현하는 변수를 초기화하고, 사용할 발판 게임 오브젝트를 미리 생성한다.
platforms = new GameObject[count] 는 발판을 저장할 공간을 만든 것이지 발판을 만든 게 아니다. 즉, 발판은 따로 만들어줘야함. 이를 for 문을 돌면서 하는 중.
for 문에서는 Instantiate() 메서드로 platformPrefab 에 할당된 Platform 프리팹의 복제본을 생성한다. 생성할 위치는 poolPosition, 회전은 Quaternion.identity 로 지정했다(Quaternion.identity 는 오일러각의 (0, 0, 0) 회전에 대응한다).
마지막 부분에는 가장 최근에 재배치 시점을 나타내는 lastSpawnTime 과 다음번 배치까지의 시간 간격인 timeBetSpawn 의 값을 0으로 초기화했다. timeBetSpawn 의 처음 값이 0으로 시작하면 게임이 시작되자마자 지연시간 없이 즉시 첫 번째 발판이 배치된다.
void Start() {
// 변수들을 초기화하고 사용할 발판들을 미리 생성
// count 만큼의 공간을 가지는 새로운 발판 배열 생성
platforms = new GameObject[count];
// count 만큼 루프하면서 발판 생성
for (int i=0; i<count; i++)
{
// platformPrefab 을 원본으로 새 발판을 poolPosition 위치에 복제 생성
// 생성된 발판을 platform 배열에 할당
platforms[i] = Instantiate(platformPrefab, poolPosition, Quaternion.identity);
}
// 마지막 배치 시점 초기화
lastSpawnTime = 0f;
// 다음번 배치까지의 시간 간격을 0으로 초기화
timeBetSpawn = 0f;
}
13.2.6 PlatformSpawner 의 Update() 메서드
PlatformSpawner 스크립트의 Update() 메서드에서는 Start() 메서드에서 만든 발판 게임 오브젝트를 돌아가며 사용하는 방식으로 발판 무한 배치를 구현한다.
1. PlatformSpawner 스크립트의 Update() 메서드 완성하기
void Update() {
// 순서를 돌아가며 주기적으로 발판을 배치
// 게임오버 상태에서는 동작하지 않음
if (GameManager.instance.isGameover) {
return;
}
// 마지막 배치 시점에서 timeBetSpawn 이상 시간이 흘렀다면
if (Time.time >= lastSpawnTime + timeBetSpawn)
{
// 기록된 마지막 배치 시점을 현재 시점으로 갱신
lastSpawnTime = Time.time;
// 다음 배치까지의 시간 간격을 timeBetSpawnMin, timeBetSpawnMax 사이에서 랜덤 설정
timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax);
// 배치할 위치의 높이를 yMin 과 yMax 사이에서 랜덤 설정
float yPos = Random.Range(yMin, yMax);
// 사용할 현재 순번의 발판 게임 오브젝트를 비활성화하고 즉시 다시 활성화
// 이때 발판의 Platform 컴포넌트의 OnEnable 메서드가 실행된다.
platforms[currentIndex].SetActive(false);
platforms[currentIndex].SetActive(true);
// 현재 순번의 발판을 화면 오른족에 재배치
platforms[currentIndex].transform.position = new Vector2(xPos, yPos);
// 순번 넘기기
currentIndex++;
// 마지막 순번에 도달했다면 순번을 리셋
if (currentIndex >= count)
{
currentIndex = 0;
}
}
}
13.2.7 PlatformSpawner 스크립트 전체 코드
using System.Transactions;
using UnityEngine;
// 발판을 생성하고 주기적으로 재배치하는 스크립트
public class PlatformSpawner : MonoBehaviour {
public GameObject platformPrefab; // 생성할 발판의 원본 프리팹
public int count = 3; // 생성할 발판의 개수
public float timeBetSpawnMin = 1.25f; // 다음 배치까지의 시간 간격 최솟값
public float timeBetSpawnMax = 2.25f; // 다음 배치까지의 시간 간격 최댓값
private float timeBetSpawn; // 다음 배치까지의 시간 간격
public float yMin = -3.5f; // 배치할 위치의 최소 y값
public float yMax = 1.5f; // 배치할 위치의 최대 y값
private float xPos = 20f; // 배치할 위치의 x 값
private GameObject[] platforms; // 미리 생성한 발판들
private int currentIndex = 0; // 사용할 현재 순번의 발판
private Vector2 poolPosition = new Vector2(0, -25); // 초반에 생성된 발판들을 화면 밖에 숨겨둘 위치
private float lastSpawnTime; // 마지막 배치 시점
void Start() {
// 변수들을 초기화하고 사용할 발판들을 미리 생성
// count 만큼의 공간을 가지는 새로운 발판 배열 생성
platforms = new GameObject[count];
// count 만큼 루프하면서 발판 생성
for (int i=0; i<count; i++)
{
// platformPrefab 을 원본으로 새 발판을 poolPosition 위치에 복제 생성
// 생성된 발판을 platform 배열에 할당
platforms[i] = Instantiate(platformPrefab, poolPosition, Quaternion.identity);
}
// 마지막 배치 시점 초기화
lastSpawnTime = 0f;
// 다음번 배치까지의 시간 간격을 0으로 초기화
timeBetSpawn = 0f;
}
void Update() {
// 순서를 돌아가며 주기적으로 발판을 배치
// 게임오버 상태에서는 동작하지 않음
if (GameManager.instance.isGameover) {
return;
}
// 마지막 배치 시점에서 timeBetSpawn 이상 시간이 흘렀다면
if (Time.time >= lastSpawnTime + timeBetSpawn)
{
// 기록된 마지막 배치 시점을 현재 시점으로 갱신
lastSpawnTime = Time.time;
// 다음 배치까지의 시간 간격을 timeBetSpawnMin, timeBetSpawnMax 사이에서 랜덤 설정
timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax);
// 배치할 위치의 높이를 yMin 과 yMax 사이에서 랜덤 설정
float yPos = Random.Range(yMin, yMax);
// 사용할 현재 순번의 발판 게임 오브젝트를 비활성화하고 즉시 다시 활성화
// 이때 발판의 Platform 컴포넌트의 OnEnable 메서드가 실행된다.
platforms[currentIndex].SetActive(false);
platforms[currentIndex].SetActive(true);
// 현재 순번의 발판을 화면 오른족에 재배치
platforms[currentIndex].transform.position = new Vector2(xPos, yPos);
// 순번 넘기기
currentIndex++;
// 마지막 순번에 도달했다면 순번을 리셋
if (currentIndex >= count)
{
currentIndex = 0;
}
}
}
}
13.2.8 PlatformSpawner 컴포넌트 설정하기
완성한 PlatformSpawner 컴포넌트를 설정하고 동작시켜본다.
1. PlatformSpawner 컴포넌트 설정하기
- 하이어라키 창에서 Platform Spawner 게임 오브젝트 선택
- Prefabs 폴더의 Platform 프리팹을 PlatformSpawner 컴포넌트의 Platform Prefab 필드로 드래그&드롭

13.3 빌드하기
빌드하기 전에 완성환 게임의 주요 기능을 확인해본다.
플레이어 캐릭터는 상황에 따라 뛰고, 점프하고, 사망하는 애니메이션을 재생한다. 게임이 시작되면 배경이 반복되고 새로운 발판이 주기적으로 게임 화면 오른쪽에 배치된다.
그리고 플레이어 캐릭터가 다가오는 발판을 향해 점프하고 무사히 착지를 할 때마다 점수가 1점씩 증가한다. 증가한 점수는 UI 로 확인할 수 있다.
만약 플레이어 캐릭터가 낙사하거나 장애물을 밟으면 게임오버되어 사망 애니메이션과 효과음이 재생되고 게임오버 UI 가 활성화된다. 게임오버 상태에서는 점포 버튼에 해당하는 마우스 왼쪽 버튼을 클릭해 다시 게임을 시작할 수 있다.
13.3.1 배경음악 추가하기
1. 배경음악 추가하기
- 프로젝트 창의 Audio 폴더에서 music 오디오 클립을 하이어라키 창으로 드래그&드롭
- 생성된 music 게임 오브젝트의 Audio Source 컴포넌트의 Loop 체크

music 오디오 클립은 반복 재생할 배경음악 파일이다. 오디오 클립을 하이어라키 창으로 드래그&드롭하면 해당 오디오 클립을 사용하는 오디오 소스 컴포넌트가 추가된 게임 오브젝트가 자동 생성된다. 오디오 소스 컴포넌트의 Loop 는 오디오 클립을 반복 재생하는 설정이다.
이것으로 유니런에서 반복 재생할 배경음악을 추가했으며, 게임의 모든 부분을 완성했다.
13.3.2 유니런 빌드하기
게임을 최종 빌드한다. 빌드하기 전에 빌드를 저장할 폴더를 적당한 경로에 미리 만들어둔다. 저자는 Uni-Run 이라는 이름에 폴더를 바탕 화면에 미리 준비했다고 함..
1. 유니런 빌드하기
- 빌드 설정 창 열기(상단 메뉴의 File > Build Settings...)
- 빌드 설정 창에서 Add Open Scenes 클릭
- Build and Run 클릭
- 탐색 창에서 빌드를 저장할 폴더로 이동
- (가능한 경우) 저장할 빌드명을 Uni-Run 으로 설정 > Save 클릭




13.4 마치며
이것으로 두 번째 예제 게임 유니런을 완성했다