Creating a Wave System for our Enemies
One of the most gratifying things in video games is the sense of accomplishment that comes with beating a difficult level or mission. Or, in our case, getting farther than our previous highest Wave.
These little reminders of your progress hit that little dopamine switch in the brain and let the Player know they’re doing a good job. And who doesn’t want to beat their previous record?! MOAR dopamine!
Spawn Manager Script
First we’ll need to create some Global variables in our SpawnManager script so we can implement our Wave System logic.
First we’ll create another private bool _spawnEnemyWave. This will be our trigger to start spawning a Wave.
Then we’ll create some integers.
- _currentEnemies = the enemies remaining in a wave.
- _enemiesInCurrentWave = the amount of enemies to be spawned in this wave
- _waveNumber = the wave we are currently on
Now we can update our SpawnEnemyRoutine():
Now in our while loop we’ve added the condition of our new bool _spawnEnemyWave.
But now, we’ve nested our Enemy spawning logic inside a for loop. This will cycle through the code and spawn however many enemies you have set the _enemiesInCurrentWave integer to.
For every enemy spawned, we add to the _currentEnemies counter.
If the Player gets destroyed, _isGameActive will be false and break the for loop — to stop spawning more enemies after death.
Then once the code has iterated through the for loop, we prepare our next Wave by adding to the _enemiesInCurrentWave (arbitrary amount) and increase the Wave number by 1.
Finally, be sure to set _spawnEnemyWave to false so that our while loop doesn’t continue, until the next wave. We’ll trigger this bool externally for the next wave!
Spawn Manager Update
Next we’ll have to have our SpawnManager continuously check if it’s time to spawn the next wave of enemies. So let’s do this in Update().
If our _currentEnemies = 0 and our _spawnEnemyWave = false, then we StartEnemySpawning(). (Ignore the boss Spawn logic for now, that will come soon ;) )
We’ll step into the UIManager script soon, but first we have to do a couple things first.
StartEnemySpawning()
Here we’re using the % operator, which looks for the remainder of a division operation.
If our _waveNumber divides by 2 and the remainder is 0, then make the spawnRate faster by 0.2 seconds. So every 2 levels, the Enemies will spawn faster! A nice little difficulty boost along with more enemies to destroy!
Decreasing _currentEnemies
We have a system that increases _currentEnemies, but have no way to decrease it, and know when we’ve destroyed the last Enemy in the current wave.
So we’ll create a public function, EnemyKilled() in the SpawnManager script that decreases the _currentEnemies by 1:
Now we can call this in the Enemy script when they are destroyed, by Player or Laser:
The UI Manager
Now we’re in a comfortable place to incorporate our UIManager script.
First we’ll create Wave Text that we can update. Similar to creating other UI Text elements, place it accordingly and adjust the parameters:
Then inside the UIManager script we’ll create a reference to the _waveText, link it in the Inspector, and create a reference to the _spawnManager and initialize at Start.
Now we’ll create the Coroutine to update the _waveText and send a message to our _spawnManaager that it’s time to start the next wave:
And back in the SpawnManager script we’ll create a couple new functions from above:
Don’t forget the Asteroid!
If you’ve been following along, you know we’re using an Asteroid to start spawning our Enemies. We’re using this interaction when the Player destroys the asteroid:
But we need to update that function to properly trigger our Wave system by adding _uiManager.SpawnNextWave():
Phew! If done correctly, we now have a Wave Spawning system! There’s a lot of Script Communication and inter script communication, but the more we get comfortable with complex Scripts, the easier it will be to read code in the future!
In the next article we’ll be creating a “powerup” that spawns, but negatively affects the Player!