A Pool with a Queue
Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 47 of 64.
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
MediumPool the footprints instead of destroying them.
- In
Trail, keep spares in aQueue<GameObject>.Return(footprint)switches it off and enqueues it;Startmakesprewarmfootprints and returns them. Get(position)dequeues a spare (or makes one), places it and switches it on.- In
Footprint, replace the Destroy: reset the age inOnEnable; afterlifeseconds,trail.Return(gameObject).
Press Play and walk: footprints fade after 1.5 seconds. 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
}
}
All lessons in Game Architecture in Unity
1Components, Not Hierarchies
Small ComponentsA Base Enemy ScriptAbstract ComponentsComponents Working TogetherRecap: Modular TurretRecap: Twin Cannon4Serialized Data
Serializable ClassesLists in the InspectorEnums in the InspectorRecap: Loot TableRecap: Roll the Loot2Interfaces in Unity
IDamageableInterfaces and TryGetComponentGetComponentsRecap: Interact KeyRecap: Nearest in ReachPractice on your own: Unity playground