큐를 이용한 풀
Coddy Unity 여정의 Unity 게임 아키텍처 섹션에 포함된 레슨. 50개 중 38번째.
풀은 여분의 오브젝트를 보관할 장소가 필요하고, C#에는 이를 위한 컬렉션인 Queue<T>가 있습니다. Enqueue는 항목을 뒤에 추가하고, Dequeue는 앞에 있는 항목을 가져오며, Count는 몇 개가 대기 중인지 알려줍니다. 이 수족관에서는 0.3초마다 기포를 하나씩 올려 보내고, 각 기포는 수면에 도달하면 풀로 돌아옵니다:
using System.Collections.Generic;
using UnityEngine;
public class BubblePool : MonoBehaviour
{
public GameObject bubblePrefab;
private Queue<GameObject> pool = new Queue<GameObject>();
private float timer;
void Update()
{
timer += Time.deltaTime;
if (timer >= 0.3f)
{
timer = 0f;
Get(new Vector3(Random.Range(-2f, 2f), 0f, 0f));
}
}
public GameObject Get(Vector3 position)
{
GameObject bubble;
if (pool.Count > 0)
{
bubble = pool.Dequeue();
}
else
{
bubble = Instantiate(bubblePrefab);
bubble.GetComponent<Bubble>().pool = this;
}
bubble.transform.position = position;
bubble.SetActive(true);
return bubble;
}
public void Return(GameObject bubble)
{
bubble.SetActive(false);
pool.Enqueue(bubble);
}
}// Bubble.cs, 버블 프리팹에 적용
public BubblePool pool;
void Update()
{
transform.Translate(0f, 2f * Time.deltaTime, 0f);
if (transform.position.y > 5f) pool.Return(gameObject);
}Get은 먼저 Count를 확인합니다. 빈 큐에서 Dequeue를 호출하면 InvalidOperationException이 발생하기 때문입니다. 그다음에야 Instantiate를 호출하고, 새 기포에만 pool 필드를 설정하면 됩니다. 재사용되는 기포에는 이 값이 이미 설정되어 있습니다. 큐는 가장 오래 기다린 기포부터 내어줍니다. 즉, 선입선출입니다. 수면에 도달한 기포는 Destroy 대신 Return을 호출하고, 비활성 상태로 씬에 남아 있다가 다음 Get 호출 때 다시 사용됩니다.
Get은 SetActive(true)를 호출하기 전에 기포의 위치를 설정합니다. 오브젝트를 활성화하면 OnEnable이 즉시 실행되므로, 그 안의 어떤 코드든 기포가 마지막으로 사라졌던 위치가 아니라 새 위치를 보아야 하기 때문입니다. 재사용 오브젝트가 다시 시작되는 시점도 이곳입니다. Awake와 Start는 기포가 만들어질 때 한 번 실행되고, OnEnable은 Get이 호출될 때마다 실행됩니다.
챌린지
중급모래 위의 발자국. 방향키로 Player를 움직일 수 있습니다(준비됨). Player에 있는 Trail.cs는 1단위만큼 걸을 때마다 Get(position)을 호출해 발자국을 남기며, 각 Footprint는 life(1.5)초 동안 유지됩니다. 현재 Get은 호출될 때마다 새 발자국을 인스턴스화하고, 발자국은 각각 스스로 파괴됩니다. 발자국을 풀링하세요:
Trail.cs에서 여분의 발자국을Queue<GameObject>에 보관하세요. Trail이 만드는 모든 발자국은trail필드를 이 Trail로 설정해야 합니다.- Start에서 풀을
prewarm(6)개의 발자국으로 채우세요. 발자국을 만들고 비활성화해 두면 첫발을 디딜 때 새로 생성되는 것이 없습니다. Get(position)은 대기열에 발자국이 있으면 하나 가져오고, 대기열이 비어 있을 때만 새 발자국을 만듭니다. 그런 다음 발자국의 위치를 설정하고 활성화합니다.Return(footprint)은 발자국을 비활성화하고 대기열에 넣습니다.Footprint.cs에서 발자국은 나이를 기록하고,life초가 지나면 파괴되는 대신trail.Return(gameObject)을 호출해 풀로 돌아갑니다. 재사용된 발자국은 다시 1.5초 동안 유지됩니다.
재생을 누르고 잠시 걸어 다닌 다음 확인을 누르세요.
직접 해보기
using System.Collections.Generic;
using UnityEngine;
public class Trail : MonoBehaviour
{
public GameObject footprintPrefab;
public float step = 1f;
public int prewarm = 6;
private Vector3 lastDrop;
void Start()
{
lastDrop = transform.position;
// 풀을 사전 준비용 발자국으로 채웁니다
}
void Update()
{
if (Vector3.Distance(transform.position, lastDrop) >= step)
{
lastDrop = transform.position;
Get(new Vector3(transform.position.x, 0.02f, transform.position.z));
}
}
public GameObject Get(Vector3 position)
{
GameObject footprint = Instantiate(footprintPrefab, position, Quaternion.identity);
footprint.GetComponent<Footprint>().trail = this;
return footprint;
}
public void Return(GameObject footprint)
{
// 여분의 발자국은 풀에서 대기합니다
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.