Complicated Pooling in Unity

Seona Bellamy
3 min readJun 3, 2021

--

In my last article I looked at Easy Pooling in Unity. Today I’m going to expand on that a little with a more complicated use case.

I ran into this recently. The game I’m building presents the player with random powerups to give them temporary extra abilities. I wanted to pool these, but I also wanted to keep them being randomly presented to the player. Using the structure covered in the previous article, the player would keep just seeing the same one or two powerups over and over since they’re infrequent enough that the first object in the pool will almost always be deactivated by the time we need to present a new powerup.

This called for a new approach to the pooling system.

Setting Up the Pool

In the PoolManager, we’re going to add the following variables to the top of the class:

[SerializeField]
private GameObject[] _powerupPrefabs;
private List<GameObject> _powerupPool = new List<GameObject>();
private int _powerupCounter = 0;

Note that this time our powerup prefab holder is actually an array. Pop back into Unity and add all of your powerup prefabs into it so we can populate the array with a random assortment.

We’re also adding a counter variable. This is so we can keep track of where we are in the list.

Now we have our GeneratePowerups() method, which will once again be called from Start().

List<GameObject> GeneratePowerups(int amount)
{
for (int i = 0; i < amount; i++)
{
GameObject powerup = Instantiate(_powerupPrefabs[Random.Range(0, _powerupPrefabs.Length)]);
powerup.SetActive(false);

_powerupPool.Add(powerup);
}

return _powerupPool;
}

The only difference between this and our Enemies example is that this time we’re instantiating a random prefab from our array of powerup prefabs.

Returning a powerup

This is where things get really different. We can no longer just loop over the pool and find the first inactive object because that will almost always be the first one. BORING! Instead, our method looks like this:

public GameObject RequestPowerup()
{
if (_powerupCounter < _powerupPool.Count)
{
if (_powerupPool[_powerupCounter].activeInHierarchy == false)
{
GameObject powerup = _powerupPool[_powerupCounter];
powerup.SetActive(true);
_powerupCounter++;
return powerup;
}
}

_powerupCounter = 0;
GameObject firstPowerup = _powerupPool[_powerupCounter];
firstPowerup.SetActive(true);
return firstPowerup;
}

We start by checking if the counter is less than the number of items in the pool list. If it is, then we check to see if the item in the list at the counter’s position is inactive. If it is, happy days! Set that object to active, increment the counter by one, and return the object for use.

If the counter has already gone beyond the length of the list, or if we’re on the last item and it’s somehow already active, then we’re going to loop back to the start of the list by resetting the counter to zero and returning the first powerup. For this reason I like to make my powerup pool reasonably large — maybe two or three times as large as my general default pool size. Not only does this mean that the first item has extremely little chance of still being active (powerups are only available for a fixed time before they disappear, even if they’re not collected) but it also means that the player is unlikely to notice the pattern repeating because the pattern is long and they’ve got other things to think about. Like the enemies shooting at them.

--

--