Spawning Waves of Enemies

Are you ready to ride the waves? My objective for this article, is to create a wave spawning system that will drop more enemies as the waves progress. My solution here is fairly quick and easy to implement, so let’s get to it!

I begin by adding a new UI Text Mesh Pro game object to the UI Manager(Canvas), titling it Wave_Text, and anchoring it to the center of the screen.

Wave is typed as a placeholder string in my Text Input dialog box, a custom font asset is dragged into the Font Asset assignment slot, and the alignment is set to be centered on the horizontal and vertical axes.

Here is how the text is currently displaying.

The UI Manager class will need a few variables to work with the new wave text and update it accordingly. The TMP_Text variable is a reference to the wave text game object, and the currentWave variable will represent the current active wave of the game. I then set the waveText active to be false in void start, which disables the object until it’s needed.

Back in Unity with the UI Manager selected, the new wave text game object is assigned to it’s respective slot via drag and drop into the inspector.

I make two public methods in the UI Manager class, to be called by the Spawn Manager for text updates. The UpdateWaveText method requires a matching int value for currentWave to be passed through. The currentWave variable on the UI Manager is then assigned the value of the currentWave variable being passed from the Spawn Manager. A coroutine is then started which will update the text to say, “Wave” and then append the wave number with the currentWave value. The wave text object is set to active, now that it is displaying the correct updated information. After waiting for 2 seconds, the text is changed to read, “Ready?”, and changed again to “GO!” after a few more seconds elapse. After a dew more seconds roll off the clock, the text object is turned off again.

Here is a video clip of the wave text display in action!

The second public method works in the same fashion, only telling the player that the “Wave 1 complete”, appending the number for which wave was completed with the currentWave variable. A few seconds later the text is updated to read, “Good Job!”.

The centering on the text is now really coming to fruition as it updates to multiple lines of text.

The player is rewarded with positive verbal reinforcement!

I can finally finish things up in the Spawn Manager. Two variables of type bool are added to work as checks for if the spawn manager is spawning, and if the wave timer has completed. I have the enemy spawn rate, which holds the value in seconds for how often enemies will be spawned in. The currentWave variable will increment as the waves increase, and pass that value to the UI Manager. Lastly, I store the UI Manager in a variable for communication. After saving, I drag the UI Manager game object into the Spawn Manager script on the inspector to assign it.

In void start, the UI Manager variable goes through a null check for errors, and then the SpawnWave method is called.

The SpawnWave method simply calls the SpawnWaveRoutine coroutine, which handles everything else. When the game starts, the currentWave variable is zero, so that value is incremented by 1, which makes the game start at wave 1. This will automatically increment and update the text accordingly from wave 1 into infinity! The enemySpawnRate variable gets decremented by 1 every time this code runs. When the game starts, this value is set to 5, so it immediately gets set to 4 for wave 1. This means a random weighted enemy will spawn every 4 seconds for as long as the wave timer is running. As the waves increase, so does the speed at which the enemies spawn! I have a check for if the enemySpawnRate is less than 1, to reassign it to be 1. This happens in wave 4, and enemies every 1 second gets hard fast. If the player needs an additional challenge, I could start dropping powerups less and less as well. I did have the enemySpawnRate decrementing into fractions less than one and well….it was getting to be a nearly impossible amount of enemies rather quickly! I also have a check for if the currentWave is equal to 3, and if it is, I send a debug.log message to the console letting me know this is the wave where the boss fight will begin!

Other than the impending boss fight, the next action as we move down the script is to set the isSpawning variable to true. This is what enables enemies and powerups to spawn in a while loop, for as long as the condition isSpawning is true. The currentWave value is sent to the UI Manager, and then I wait for 6 seconds, which is how long it takes for the wave text routine to finish. Both coroutines for spawning enemies and powerups are started, and then I wait for 10 seconds. This 10 seconds is how long each wave will last. I will later set it to 30 seconds, but for testing purposes, short 10 second waves is doing the trick. After the timer expires, isSpawning is set to false to stop the enemy and powerup spawning, the isWaveTimerComplete variable is set to true, and the method for finding remaining enemies is called.

The FindEnemiesRemainingRoutine method does exactly that. It operates in a while loop that needs the isWaveTimerComplete variable to be true to run. It’s a good thing we just set that to be true! The if statement looks for game objects with the Tag of enemy to be null. If enemies are found, the statement will return and run again every 2 seconds. This time measure is important here so I don’t crash the program or over work the game machine or computer playing it. Once no enemies are remaining, the isWaveTimerComplete variable is reset to false, which will keep this loop from running again. The UI Manager is then told to run the WaveCompletedText method. After waiting 6 seconds for the wave completed text routine to finish, the SpawnWave method is called again, and the infinite wave spawner has come full circle!

Thanks for reading along, and I hope you join me in my next article where I begin to work on the boss battle!

I am an artist and musician, that is currently diving headfirst into game development with C# and Unity3D.