발판을 무한 반복 생성하여 배치하는 발판 생성기를 구현하자.
가장 간단한 방법은 매번 새로운 발판을 생성하는 것인데,
이 방법은 발판 오브젝트를 kill하지 않기 때문에, 메모리 사용량이 계속 증가하는 문제가 있다.
따라서 Object Pooling 방식으로 발판을 생성/관리하도록 하자.
Object Pooling은 Object를 미리 만들어서, Pool에 쌓아두는 방식이다.
Pool에 Object를 생성해두고, 필요하면 생성 대신, Pool의 Object를 가져다 쓴다.
필요 없다면 파괴하는 대신, 비활성화하고 Pool에 반환한다.
- Instantiate() 또는 Destroy() 메서드는 오브젝트를 실시간으로 생성/파괴하는데, 성능을 많이 먹으며 GC를 유발하기 쉽다. 이것은 게임 중 Freeze를 겪게 만든다.
기존 Object를 재활용하는 방식을 통해, 간단한 발판생성기를 완성하는 것이 목표이다.
오브젝트 풀링을 통한 발판 무한배치
- 3개의 발판을 미리 생성하자.
- 이 3개의 발판을 계속 로테이션돌린다.
- 각 발판은, ScrollingObject Component를 보유하게 하여 항상 왼쪽으로 이동하게 한다.
PlatformSpawner.cs 스크립트 작성
Start 시점에 미리 Instantiate를 호출한다.
void Start() {
// 변수들을 초기화하고 사용할 발판들을 미리 생성
platforms = new GameObject[count];
for(int i = 0; i < count; i++)
{
platforms[i] = Instantiate(platformPrefab, poolPosition, Quaternion.identity);
}
lastSpawnTime = 0f;
timeBetSpawn = 0f;
}
void Update() {
// 순서를 돌아가며 주기적으로 발판을 배치
if(GameManager.instance.isGameover) return;
if(Time.time >= lastSpawnTime + timeBetSpawn)
{
lastSpawnTime = Time.time;
timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax);
float yPos = Random.Range(yMin, yMax);
platforms[currentIndex].SetActive(false);
platforms[currentIndex].SetActive(true);
platforms[currentIndex].transform.position = new Vector2(xPos, yPos);
currentIndex++;
if(currentIndex >= count) currentIndex = 0; // 마지막 순번이라면 순번리셋
}
}
전체 스크립트
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() {
// 변수들을 초기화하고 사용할 발판들을 미리 생성
platforms = new GameObject[count];
for(int i = 0; i < count; i++)
{
platforms[i] = Instantiate(platformPrefab, poolPosition, Quaternion.identity);
}
lastSpawnTime = 0f;
timeBetSpawn = 0f;
}
void Update() {
// 순서를 돌아가며 주기적으로 발판을 배치
if(GameManager.instance.isGameover) return;
if(Time.time >= lastSpawnTime + timeBetSpawn)
{
lastSpawnTime = Time.time;
timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax);
float yPos = Random.Range(yMin, yMax);
// 발판 보드젝트를 껐다켜서, 해당 발판 게임 오브젝트의 상태를 리셋한다.
// Platform 스크립트는 발판의 상태를 리셋하고 무작위로 장애물 오브젝트를 활성화한다.
platforms[currentIndex].SetActive(false);
platforms[currentIndex].SetActive(true);
platforms[currentIndex].transform.position = new Vector2(xPos, yPos);
currentIndex++;
if(currentIndex >= count) currentIndex = 0; // 마지막 순번이라면 순번리셋
}
}
}
일단 Hierarchy상에서, Platform Spawner를 만들고, Prefabs를 넣는다.
플레이해보면, 랜덤발판생성이 구현되었다는 것을 알 수 있다.
Scene창을 보면, 발판을 돌려쓰는 것을 확인할 수 있다.
음악넣기
별것없다. 드래그 딸깍 하자.
버그가 있는것같은데,
Deadzone을 아래로 잡았음에도, 갑자기 뭐랑 Collision된건지 죽는다.
이건 추후 디버깅해야할 이슈로 남겨놓자.
빌드하기
동일하다.
배운것
- OnEnable() 메서드는, Component 활성화마다 매번 실행된다.
- Object Pooling이라는 방법이 있다.
'Development > Unity Engine' 카테고리의 다른 글
[Retro유니티] LightMap과 Baking (0) | 2024.12.09 |
---|---|
[Retro유니티] ZombieSurvivor - 레벨 아트 사용 (1) | 2024.12.08 |
[Retro유니티] 발판 밟을 시 점수+=1 구현 (0) | 2024.11.27 |
[Retro유니티] 배경 구현, 배경스크롤링 구현 및 Deadzone 구현 (0) | 2024.11.23 |
[Retro유니티] 2D 충돌구현 - OnTriggerEnter2D / OnCollisionEnter2D / OnCollisionExit2D 오버라이딩 (1) | 2024.11.23 |