Feature: Spawning Waves

Kyle W. Powers
5 min readMay 16, 2021

This article will show how to spawn waves of Enemies using ScriptableObjects, which will allow easy plug-and-play functionality.

A ScriptableObject is a data container that you can use to save large amounts of data, independent of class instances. One of the main use cases for ScriptableObjects is to reduce your Project’s memory usage by avoiding copies of values.

UIManager

The first thing we will set up is the UIManager script. We need some variables for the new Text objects and a new float for the Next Wave Text flicker duration. We will use the flicker delay from the Game Over Text.

This method will update the Wave Text with the current Wave and max waves passed in and ensure the current Wave is not less than zero.

This Coroutine will flicker the Next Wave Text for the set duration.

This method can be called from other scripts to flicker the Next Wave Text.

Enemy and Wave ScriptableObjects

To create a ScriptableObject, you create a new script that inherits from the ScriptableObject class, specific to Unity like MonoBehaviour. You then can use the CreateAssetMenu attribute above the class for easy creation of ScriptableObjects in Unity. All that the EnemyType needs for a variable is a GameObject to hold the set Enemy Prefab.

Creating an Enemy ScriptableObject.

The Wave class needs a List of EnemyTypes to hold the Enemies in that Wave.

Creating a Wave ScriptableObject.

SpawnManager

In the SpawnManager script, we now need to set it up to use the Waves. To do this, we need to add some new variables. The first is an array of Waves to hold the Wave ScriptableObjects. Next are three int variables, one to keep track of what Wave the SpawnManager is spawning from, the second for the total number of Waves in the array, and the last is the index of the Enemy in the current Wave’s List that should be spawning. Now we need three bools, one to know when to stop spawning Enemies, one for when to stop spawning Power-Ups, and the last to see if we should count the number of Enemies in the scene. The final thing we need is a reference to the UIManager to call methods for the Wave Text.

In Start, we set the number of Waves, get the reference to the UIManager and update the Wave Text.

In Update, we will check the number of Enemies in the scene by checking the Enemy Container children. If there are zero Enemies in the scene, we tell the Power-Ups to stop spawning and start the next Wave.

Now to convert the SpawnEnemyRoutine to spawn from the Wave. The first thing that needs to be done is to get the current Wave, reset the current Enemy, and keep track of the active Enemies. We will keep spawning Enemies till the current Enemy index is greater than the number of Enemies in the Wave minus one. To spawn the Enemy, we will get the EnemyType from the Wave List and then get the GameObject Prefab.

The only thing to change in this Coroutine is the while loop condition to the new bool. That will allow Power-Ups to keep spawning after the Enemies have stopped.

In StartSpawning, we will check that we have not reached the end on the Waves array. If we haven’t, we will enable the Power-Ups and Enemies to start spawning, start the Coroutines, update the UI and let the Player know a new Wave is coming.

Finally, add the new bool for the Power-Ups to the StopSpawning method.

On the Spawn Manager GameObject, you can use the Wave ScriptableObjects in any order you want.

When playing the UI updates for the Waves and the Enemies spawn according to the Wave.

--

--