Menu
CoddyTech

큐를 이용한 풀

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이 호출될 때마다 실행됩니다.

challenge icon

챌린지

중급

모래 위의 발자국. 방향키로 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)
    {
        // 여분의 발자국은 풀에서 대기합니다
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Unity 게임 아키텍처의 모든 레슨