Menu
CoddyTech

A Pool with a Queue

Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 38 of 50.

A pool needs somewhere to keep its spare objects, and C# has the collection for it, Queue<T>: Enqueue adds an item at the back, Dequeue takes the one at the front, and Count says how many wait. This aquarium sends up a bubble every 0.3 seconds, and each bubble comes back to the pool at the surface:

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, on the bubble prefab
public BubblePool pool;

void Update()
{
    transform.Translate(0f, 2f * Time.deltaTime, 0f);
    if (transform.position.y > 5f) pool.Return(gameObject);
}

Get checks Count first, because Dequeue on an empty queue throws an InvalidOperationException. Only then does it Instantiate, and only a new bubble needs its pool field set: a reused one still has it. The queue hands out the bubble that has waited longest, first in, first out. A bubble at the surface calls Return instead of Destroy, and stays in the scene, inactive, until the next Get.

Get places the bubble before SetActive(true), because switching it on runs its OnEnable straight away, and anything there should see the new position, not where it last vanished. That is also where a reused object starts over: Awake and Start ran once, when the bubble was made, and OnEnable runs on every Get.

challenge icon

Challenge

Medium

Footprints in the sand. The arrows walk the Player (ready). Trail.cs, on the Player, drops a footprint every 1 unit walked by calling Get(position), and each Footprint lasts life (1.5) seconds. Today Get instantiates a new footprint every time and each one destroys itself. Pool them:

  • In Trail.cs, keep the spare footprints in a Queue<GameObject>. Every footprint the Trail makes needs its trail field set to this Trail.
  • In Start, fill the pool with prewarm (6) footprints, made and switched off, so the first steps make nothing new.
  • Get(position) takes a footprint from the queue when it has one, and makes a new one only when it is empty; then it places the footprint and switches it on.
  • Return(footprint) switches the footprint off and puts it in the queue.
  • In Footprint.cs, a footprint counts its age and, after life seconds, goes back with trail.Return(gameObject) instead of being destroyed. A reused footprint lasts its full 1.5 seconds again.

Press Play, walk around for a while, then Check.

Try it yourself

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;
        // Fill the pool with prewarm footprints
    }

    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)
    {
        // Spare footprints wait in the pool
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Game Architecture in Unity