In this lecture, we're going to get our enemies spawning over time in our waves.
And because it's just a small step to get our waves working, we're also going to implement multiple
waves.
So let's start by heading over to our wave config script, because in here we're going to want to specify
the spawn time for each enemy in the wave.
So let's create a new serialized field of type float called Time Between Enemy Spawns.
While we're here, we can give it a default value.
So maybe around one per second for now.
And rather than giving all of the enemies a fixed arrival time, let's add a little bit of variance
in there.
To do this, we're going to need two more variables to keep things working correctly.
So we're going to have a float called spawn time variance, and we're going to add or subtract this
value from our time between enemy spawns to add that element of randomness.
But if you don't want any randomness, we can still use this approach and just set our spawn time variance
to zero.
And because this is going to be added or subtracted from our time between enemy spawns, if we happen
to set a larger variance which is above the value for our time between spawns, we could end up in some
negative numbers.
So this is what the third variable is going to control and this is going to be a float called minimum
spawn time.
And we can set that to around 0.24 now.
So with those set up, let's create the getter method that's going to return our random spawn time.
We scroll all the way down to the bottom and create a public float.
Get random spawn time.
First of all, we're going to want to store a random range in a float so that we can return that after
we've done some adjustments.
So we'll create a temporary variable of type float called spawn time, and this is going to return a
random range between our time, between enemy spawns minus our spawn time variance.
And if we put the next part on a new line, the maximum value is going to be the time between enemy
spawns plus the spawn time variance.
Then to cap this lower bound just in case this goes below our minimum spawn time threshold.
We're going to return math f dot clamp.
The value we want to clamp is going to be our spawn time.
Our minimum value is going to be the minimum spawn time.
And for the maximum value we're going to hold the maximum number that a float can hold.
And we can do that with float dot max value.
So with that set up, let's head over to our enemy spawn and actually get our enemies arriving over
time.
If we head down into our spawn enemies method, we've already written the loop to create the enemies.
So we just need a way of delaying this loop for every iteration.
And we can do this using something called a CO routine.
Now, routines are kind of like methods, but they're written and executed slightly differently.
The first step to setting up a routine is to give our method a new return type.
So we're going to change this from void to be an AI enumerator.
Now, you don't have to worry too much about what an enumerator is.
You can really just think of this as the method returning something countable that you can keep track
of.
This is giving us a red squiggly error message for our method name, and it's saying that not all code
paths return a value.
So like a method with a return type, we do need to return something.
But unlike a method, we do this in a slightly different way.
So inside of our for loop, once we've gone round once we're going to want to break out of this code
routine and wait for a certain amount of time.
And to do this, we're going to need to yield control from our code routine back to unity.
So our return type for our code routine is going to be yield return, and then we need to return something.
Now, if we wanted this to execute straight away, we could return null.
But in our case, we want to wait for a set number of seconds.
So we're going to return a new wait, 4 seconds.
And we can see in this list here, we've got a few different options.
We've got wait until the end of the frame.
We've got wait until the end of the fixed update loop.
But the one we want is wait 4 seconds.
And the amount of time we want to wait is going to be coming from our wave config so we can say current
wave dot get random spawn time.
And this is essentially the routine saying that it's done what it needs to do for now and to come back
and check on it in a number of seconds.
Once that time has elapsed, unity will check back in on our routine and say that you asked me to come
back in a number of seconds to see if you had anything else to do.
And our code routine is going to enter the next loop of our for loop, at which point it's going to
instantiate our second enemy and then yield control for another amount of seconds.
This loop will continue until we've gone through all of the enemies in our list, at which point our
code routine will break out of its for loop and come to a close.
So hopefully that logic makes sense, but let's see it in action.
And before we can do that, we do need to call a routine slightly differently to a method as well.
So up in our start method where we're currently calling a method called spawn enemies, now we need
to start a code routine and we can do that by writing start code routine and then placing the method
that we want to start in parentheses.
So let's save up our script and see this in action, in unity.
Before we go ahead and play, though, let's check on our waves in our Waves and Paths folder.
And if we click on Wave Zero, which is one we're currently playing within the scene, we can see that
we've got these three new variables.
So we've got our time between enemy spawns, which is around a second and a spawn time variance of zero.
To add some randomness, I'm going to set this to around 0.5.
So our enemies will now appear between half a second and one and one half seconds between each other.
Now, if we go ahead and hit play, we'll find that our enemies are now nicely spaced out.
So adding this time is allowing us to space out the execution of our for loop.
The next step of our game is going to be to execute multiple waves.
So let's head back over to our enemy spawn script and see how we're going to do this.
Well, we're again going to need a couple of new variables and the first is going to be a list of wave
configs.
So let's create a serialized field and have a list of wave config essos.
AMA.
Call this the wave configs.
And because we now have all of our WAV configs in this list, we don't need to have this current wave
serialized anymore.
What we're going to do is we're going to populate that based on the current wave from our list.
Finally, just like how we have space between our enemies appearing, we may want to have space between
our waves appearing.
So let's add another serialized filled for that.
It's going to be a float and it's going to be the time between waves.
And by default, we're not going to have any space at all.
So once one wave has generated all of its enemies, we're going to jump straight into the next one.
But if you do want to slow that down, then you have some control.
If you want even more control, then we can take a similar approach to our enemies from our wave config.
But I'm not going to worry about that too much.
I'm just going to have a fixed amount of time between each wave and to loop through all of the waves
in our list.
We're also going to do that in spawn enemies.
But rather than walk you through it step by step, I think it's time for your challenge.
I want you to loop through our new list of wave configs.
And when you're looping through this list, have a think about whether you can use A for each loop for
this or whether you need a for loop.
And to clarify the logic for what we need to do in each loop, we need to set the value for our current
wave because this is going to be very important for our path finder.
We then want to loop through all of the enemies in that wave.
So that's the code we've already got in place.
And then after all of the enemies have been spawned for that wave, we want to wait for the time between
waves before generating the next one.
So pause the video now and give that a go.
Okay.
Welcome back.
So let's get our waves working in our sworn enemies.
We need a new loop to go through all of our wave config script through objects.
And for this you could use a for loop, but I'm going to use a for each loop because we need to loop
through all of them and we don't need to keep track of an iterator like we did for our enemies so we
can say for each wave config S0 and we'll call this the wave in our wave configs list.
Then we want to set our current wave equal to the wave that we're currently on.
For this loop, we then want to take our existing for loop and place that inside of our for each loop.
And then after that four loop has completed, we need to yield return new wait 4 seconds and this time
we're going to wait for the time between our waves.
Now, before we go ahead and test, rather than calling this spawn enemies, it's now spawning all of
our waves and enemies.
So to keep our method names descriptive, let's rename it to spawn enemy waves, save our script and
jump back over into unity.
And then on our enemy spawn, we now need to set up our wave configs again.
So if we look the inspector, we can now select multiple things in our project window and drag them
over into our list.
Let's unlock the inspector so we don't run into problems.
We select our enemy spanner.
And I'm going to set the time between waves to 2 seconds.
Now, before we hit play, we've set up our wave zero, but we haven't set up wave one yet.
So let's go into wave one and add some enemies to our list.
Strike over an enemy into our list and duplicate that a few times.
So I'm going to again go with three for this wave.
And for this one, I don't think I'm going to go with any variants for our spawn time, so let's test
this out by hitting play.
And we can say our first wave is being generated with some random variance in the enemy arrival.
And then once that's finished, the second wave gets generated.
If we set our time between waves to zero and play again, we'll see that the second wave arrives a lot
sooner.
So even before the first enemy wave has finished traversing the screen.
And with that we have a nice functioning wave system and at this point we could go ahead and start creating
more waves to add to our list.
But regardless of how many we add, we are eventually going to get into a state where these waves come
to an end, at which point we may want to transition to a game over or a wind screen, or in my case,
I want these to infinitely loop.
So once we get to the end of the list, we want to jump back up to the top.
That's what we're going to be doing in the next lecture.
So I'll see you there.