Enemy Waves with Scriptable Objects
Objective: Create waves of enemies using scriptable objects.
Create a new scene and add a plane for the ground. Now add a Cube, Cylinder and Sphere to the scene, tagging these as Enemy. Drag these enemies into your Prefabs folder and delete from the hierarchy. Next create a new script named Wave which inherits from ScriptableObject. The CreateAssetMenu allows a newWave to be generated by right clicking on a folder in the project’s Assets to create ScriptableObjects > Wave. Wave contains the waveSequence, which is a list of GameObjects to be spawned for that wave. Create three newWaves: renaming Wave_0, Wave_1 and Wave_2.
The order for enemies in each wave can be assigned by selecting, for example Wave_1, and dragging the enemy prefabs into the waveSequence. Repeat this process for Wave_0 and Wave_2. Three are used for each Wave in this example, but any number of enemies could be used.
Next create an empty game object and name it Spawn_Manager then add a new script called Spawner. This script requires five private variables: _spawnName, _enemyWave, _spawnPoints, _currentWave and _instanceNumber.
The variables _spawnName, _enemyWave, _spawnPoints all utilize SerializeField so that they can be assigned in the inspector as shown below. The _enemyWave is a list of Wave scriptable objects. SpawnPoints is an array of Vector3 positions. The _spawnName is the name that will be used for instantiated objects.
The Spawner script then starts the StartWaveRoutine, which manages enemy waves. While the _currentWave is less than the _enemyWave.Count, another IEnumerator, SpawnEnemiesRoutine, is used to generate enemies within the wave. After 5 seconds all activeEnemies are found using their tag and destroyed using a foreach loop. The _currentWave is incremented, eventually exiting the while loop after all waves are completed.
The SpawnEnemiesRoutine() begins by setting the currentSpawnPointIndex to zero. A for loop is started for the length of the waveSequence for the _currentWave, which instantiates each enemy GameObject obj to currentEntity and renames it using the _spawnName + _instanceNumber. The currentSpawnPointIndex and _instanceNumber are then incremented. The routine then yields for one second before proceeding.
The use of a Wave list, _enemyWave, within the Spawner allows each _enemyWave to be assigned in the inspector. Each Wave is itself a list which is assigned in the inspector using a scriptable object. Scriptable objects allow a list of lists, all assigned in the inspector.