Creating a Wave System for the Enemies

Christian Carter
3 min readAug 30, 2021

--

This tutorial covers creating a wave system for the enemies. This will limit a certain number of enemies at a time and wait for the player to destroy all the enemies in the wave before starting a new wave. To start you will need to create a UI element for the Wave. This will tell the player what wave they are on. This is not covered in this tutorial. If you need a review of how to create a UI element refer to this tutorial.

First, got to the SpawnManager script and add variables for the wave, the number of enemies, the number of enemies to spawn, the move type of the enemies as an int, and one to for the UIManager. Make sure you assign the UIManager variable in the Start function.

private int _waveNumber;
private int _numEnemies;
private int _numEnemiesToSpawn;
private int _moveType;
private UIManager _uiManager;

Next, create a function that reduces the number of enemies. This will be called by the enemy when they die.

public void OnEnemyDeath()
{
_numEnemies--;
}

Then go to the Enemy script and add a reference to the SpawnManager. Make sure you initialize it. Then where you handle the death of the enemy use the OnEnemyDeath function you just created.

_spawnManager.OnEnemyDeath();

Next, add a function to handle the initialization of an enemy. This should take two inputs, one for the move type and one for if shields are active.

public void InitializeEnemy(int moveType, bool hasShield)
{
_moveType = moveType;
SetMoveDirection();
if (hasShield == true)
{
ActivateShield();
}
}

Remove any other spots that you set the move type, like in the Start function. Make sure your SetMoveDirection function is setup for all the moves you want to have.

Return to the SpawnManager script. Now you will update the SpawnEnemyRoutine. To do this add an if-else statement. Check if the number of enemies is 0. If it is start a new wave. Increment the wave number. Set the number of enemies to the wave number times two. This way the number of enemies will continue to increase. The number of enemies to spawn will start the same as the number of enemies. These will be used for separate purposes. The number of enemies is reduced as enemies are killed and used to know when to start a new wave. The number of enemies to spawn will help keep track of how many more enemies need to spawn in the wave. All enemies in a wave have the same move type. Reduce the wave number by 1 and then take the modulo of using the number of move types. Then update the wave number in the UI.

if (_numEnemies == 0)
{
_waveNumber++;
_numEnemies = _waveNumber * 2;
_numEnemiesToSpawn = _numEnemies;
_moveType = (_waveNumber - 1) % 4;
_shieldTrigger = ((_waveNumber - 1) % 12) / 4;
_uiManager.UpdateWave(_waveNumber);
}

Then in the else statement is where you will instantiate and initialize the enemy. First check that there are still enemies to spawn. Then set if the enemy will have a shield. In the example below it is set for four waves with no shields, 4 waves with every other enemy shielded, and then for waves with all enemies shielded. It then instantiates the enemy as before but the calls InitializeEnemy passing it the move type and if it should have a shield. Remember to add the line to decrement the number of enemies to spawn at the end.

else
{
if (_numEnemiesToSpawn > 0)
{
bool hasShield = false;
switch (_shieldTrigger)
{
case 0:
hasShield = false;
break;
case 1:
if (_numEnemiesToSpawn % 2 == 1)
{
hasShield = true;
}
break;
case 2:
hasShield = true;
break;
default:
hasShield = false;
break;
}
Vector3 posToSpawn = new Vector3(Random.Range(-8.0f, 8.0f),
7.0f, 0);
GameObject newEnemy = Instantiate(_enemyPrefab,
posToSpawn, Quaternion.identity);
Enemy enemy = newEnemy.GetComponent<Enemy>();
enemy.InitializeEnemy(_moveType, hasShield);
newEnemy.transform.parent = _enemyContainer.transform;
_numEnemiesToSpawn--;
}
}

That is all you need to implement a wave system for the enemies.

-Chris

--

--