Balanced Spawning System

How to Spawn based on a distribution table

Tristan Engel
3 min readJul 21, 2021

As stated in the title today we will create a spawning system based on a distribution table. This will allow us to spawn simple enemies more frequent and harder enemies less frequent. Same goes for the powerups.

Distribution Table

We could just hard code all the chance something happens, but that will be difficult to adjust the values later on when balancing our game. This is why we use a distribution table. A distribution table will hold all values is which distribution they will occur.

An example

Common 5, Rare 2, Epic 1
Our total of all values combined will be 5+2+1=8.
Next we roll an 8 sided dice. Then look at our table like below. So if the outcome is 6 we drop a rare item.

1 Common
2 Common
3 Common
4 Common
5 Common
6 Rare
7 Rare
8 Epic

Flexibility

When we adjust the values like Common to 10, the distribution changes. The total will change and the random number range(dice sides) changes.
In our code we will add all the weights in the table and calculate the total and based on the total we will calculate the random number range.

Distribution Table Script

Only the script for the distributed spawning system of the powerups is displayed below. The same logic and nearly the same code is used for spawning of enemies.

Variables

The code for the variables are below. The last two variables are only SerializedFields for debug purposes.

[SerializeField] private float _minPosX, _maxPosX, _startPosY;

//power up config
[SerializeField] private float _minSpawnIntervalPowerup = 3f;
[SerializeField] private float _maxSpawnIntervalPowerup = 7f;

[SerializeField] private int[] _powerUpWeightTable;
[SerializeField] private GameObject[] powerUpsPrefabs;
[SerializeField] private int _total = 0;
[SerializeField] private int randomNumber;

Assign in Inspector

In the Inspector it looks like this after assigned the weight values and prefabs:

Calculation which Powerup to spawn

First we calculate the total of the weights with an foreach loop in Start().

foreach (var weight in _powerUpWeightTable)
{
_total += weight;
}

Next have a while loop to continuously spawn power ups with some random time between each spawn and a random position to spawn.

The distribution table based calculation starts from the comment :
//spawn random powerup

A random number is generated based on the total. Using a for loop we check if the generated number is smaller or equal to the 1st value of the table. If not (else) we subtract the value of from the random number. By repeating this till the value is equal or smaller then the current leftover random number we can figure out which powerup is linked to the value and spawn it.
The break is needed so the game doesn’t continue to subtract and find following powerups to spawn.

while (_stopSpawning == false)
{
//random spawn time
float spawnIntervalPowerup = Random.Range(_minSpawnIntervalPowerup, _maxSpawnIntervalPowerup);
//wait first
yield return new WaitForSeconds(spawnIntervalPowerup);
//random spawn pos
Vector3 spawnPos = new Vector3(Random.Range(_minPosX, _maxPosX), _startPosY, 0);

//spawn random powerup
randomNumber = Random.Range(0, _total);
for (int i = 0; i < _powerUpWeightTable.Length; i++)
{
if (randomNumber <= _powerUpWeightTable[i])
{
Instantiate(powerUpsPrefabs[i], spawnPos, Quaternion.identity);
break;
}
else
{
randomNumber -= _powerUpWeightTable[i];
}
}
}

--

--

Tristan Engel
Tristan Engel

Written by Tristan Engel

Aspiring developer that’s self-learning Unity & C# to transition to a career with Unity. I got a passion for creating interactive experiences.

No responses yet