March 5, 2019
Tower Defense Tutorial
Episode 25 – Fading
Youtube – How to make a Tower Defense Game (E25 WAVE SPAWNER 2.0) – Unity Tutorial
By: Brackeys
Ep. 25
This tutorial focuses on updating the wave spawner to be a more useful and versatile tool.
One of the first changes was to have the next wave spawn some time after the previous wave has been killed off instead of having it on an overall set counter. We create a public static int, EnemiesAlive, to constantly hold this value of how many enemies are alive in the current wave. We then let the Die method in the Enemy script and the EndPath method in the EnemyMovement script remove one from this value before destroying the enemy object. Since we are already referencing this in multiple somewhat unrelated areas, I think there might be a nicer way to reference one method somewhere that destroys the enemy gameobject as well as removing one from this global counter.
Another issue I am already noting here are that there might be strange cases where the enemy is killed almost immediately upon leaving the spawn, so enemies will be 0 already at that time and this may start the next wave spawning. It may be better to have the system just know how many enemies will be in the wave ahead of time and set the EnemiesAlive value to that at the very start of the wave, then subtract from this value when enemies are destroyed and let the next wave start when that value is 0.
Currently the WaveSpawner only holds a single enemy prefab to be the enemy to spawn. As most tower defense games do, we want to have a system that can spawn multiple types of enemies. To begin, we created a new Wave Class to hold the information needed for any particular wave. Since this is its own unique class, make sure to remove the Monobehaviour tag from the class. We also added [System.Serializable] to this class so it would show up in the editor. The values we created for this were:
- public GameObject enemy – to hold the enemy prefab to spawn for this wave
- public int count – to determine the number of enemies to spawn in this wave
- public float rate – how fast each individual enemy in the wave spawns (1 over time between spawns)
To continue on the thought that we want to be able to have control over the individual waves, including having different enemy types, we created an array in our WaveSpawner script to replace the single enemy prefab gameObject we had before. This array would also be an array of the Wave class instead of gameObjects.
”It’s not as automated… but it gives us so much more configuration possibilities and really allows us to create something that’s much more fun for the end user. Having this idea of a wave that is kind of an object that we’ve created on our own with these different characteristics, then storing a bunch of these waves in a list, then going through them one by one and using some of the properties in there to create different behaviors is kind of the core of object oriented programming.”
Now our IEnumerator method SpawnWave grabs the next Wave in our array of Waves and uses all of its information. The enemy prefab was replaced with wave.enemy, the time between spawns was replaced with 1/wave.rate, and the number of times to go through the for loop was changed to wave.count.
Finally, to take advantage of this new system, we created some new enemy types, Tough and Fast, to go with our existing enemy which is now just the Simple enemy type. We created an entire Enemy folder, then gave each type of enemy their own folder to hold the gameObject prefab, the material, and the particle system death effect for that specific enemy. This seems like an effective organizational pattern to follow for holding different enemy types.
To edit the individual waves we want to create, we currently did that in the editor. In our WaveSpawner script, since we made the Wave class serializable, we could see our Wave array along with all the individual public variables associated with the individual waves in the array. We had to go to each one specifically to enter the enemy prefab for that wave, the number of enemies to spawn, and the rate at which they spawn. While this does give us a lot of control, there may be efficient ways to automate some of this process for longer scaled gameplay.
LEARNING PRACTICE
Good practice for learning to use your own classes: create a pretty basic method for a core functionality (like our spawner), then try to replace some of the main variables in it with those in a user defined class you make (like our Wave variables that replaced those in the spawner script). This is basically what we did in this tutorial since we had a very bare bones spawner but then updated it to work better with various types of enemies instead of just one. It really helped me understand, not only how to use a user defined class, but also how to effectively set one up.
SUMMARY
- Keycode Shortcut – Visual Studio: with a piece of code highlighted, hold Alt + arrow key to move that code up or down a line
- When you know you will create a lot of a certain type of object, creating a class that holds the key properties for that type of object is necessary
- Newer versions of Unity allow for Prefab variations which might be worth looking into for our enemy prefabs (New duplicated versions worked fine for now though)