Hi, everyone. I'm Jeremy Bond, and welcome back.
In this video, we're going to take a look at how I
implemented the multiple levels in the Asterax game.
To start with, let's take a look at the Asterax script.
You can see here that Start which used to
actually instantiate asteroids is much shorter now.
All it does is parse level progression,
and then set the asteroids list to be empty,
and set the score to be zero.
So, let's take a look at this ParseLevelProgression.
This pulls again the level progression string and parses it to generate different levels.
You can see the ParseLevelProgression makes many calls to the split method of strings,
which takes a string and splits it based on a certain character into an array of strings.
The first is on the coma,
which splits it into individual levels,
then on the colon,
which splits out the level number from the three/two for instance,
and then on the slash which gives us the three and the two,
and then we parse each of those the three and the two as integers.
If anything doesn't work out in this splitting,
we get an error logged to the console.
So, once we parse this out,
it all goes into a LevelInfo struct.
So, let's take a look at how that struct works.
So, structs are very similar to classes,
except that a struct is parsed by value while a class is parsed by reference.
So, that means, if I were to have a list of class instances,
and I parsed around that class instance,
there really still just be one and multiple things
would have references to the same chunk of data in memory.
A struct on the other hand,
anytime I parse it to something else,
it makes a copy of it.
You've experienced this behavior with Vector3's in Unity.
That's a very common thing that is parsed by value instead of parsed by reference.
So, our LevelInfo is parsed by value, it is a struct.
And as a struct,
we have a constructor which is the public LevelInfo on line 516,
and we parse in the level number,
the name of the level,
the initial number of asteroids,
which are the number of parent asteroids,
and then the number of sub-asteroids per level.
So again, on level one that struct is three
with three parent asteroids and two sub-asteroids,
which means each parent asteroid will have
two size two asteroids and each size two asteroid,
will have to size one asteroids attached to it.
So, now that that's all set up with all the levels, how do we start the game?
Well, on the title screen panel,
there is a button, here,
that says "start on it" and you click
the button and the button calls "TitleScreenPanel.StartGame".
So, let's struck that down.
StartGame calls asterax.StartGame.
Asterax.StartGame is a static method,
which means it will be difficult for us to
call it from the button in the unity-inspector,
which is why I've added this TitleScreenPanel StartGame method
to then call the static method on asterax.
Let's struck that method down.
Here, the struct game method sets the game level to zero,
which you can see just above it,
is an automatic property.
So, it's a static automatic property,
it has a getter that is public and a private setter.
So, only asterax can set the game level,
but everything else can get the game level.
Then on the second line of the StartGame method,
we call _S.EndLevel, which calls EndLevel on the singleton instance of Asterix.
Let's take a look at that. Now, this is a common thing that I do.
By calling EndLevel to start the game with game level zero,
then the game level with increment on line 186 here to game level one,
and then go through the same process that happens whenever I end a regular level.
This means I don't have to have a special case for the beginning of the game,
I just have a non-existent level zero,
which then ends and allows level one to start.
So, here you can see that if the GAME_STATE is not GameState.none,
and the GAME_STATE is only set to GameState.none when the game ends.
So, this is just to make sure that we don't try and
start a new level right as the game is stopping.
So, I'm going to set PauseGame to true.
I'm going to increment the game level,
going to set the game state to eGameState.postLevel.
So, it's right at the end of a level.
Then I'm going to call the LevelAdvancePanel that AdvanceLevel.
I'm going to pass it two different callbacks.
So, AdvanceLevel, let's go take a look at it.
So, AdvanceLevel inside the LevelAdvancedPanel set up these two callbacks
that we passed in as a displayCallback and
idleCallbacks on the level advanced panel singleton,
then it sets the state to fadeIn.
So, what happens then? We go to set state,
and then we set the state to fadeIn.
Now, I'm going to go into more of the details
of the various states of this when I talk about the bonus challenge,
but the important thing to know here is that
the LevelAdvancedPanel flows through multiple states,
and then eventually gets to a point where it calls the first of those callbacks.
So, we scroll down and you see here that when it gets to the displayState,
which is where everything has faded in,
then it's going to call displayCallback if it is not equal to null.
So, this is a delegate displayCallback,
and then it calls the callback and
then sets the callback to null so that it won't be called again.
So, let's go look at this displayCallbacks.
So, that is going to be back in Asterax,
the LevelAdvancedDisplayCallback right here.
So, when that is called back,
it calls StartLevel, and this is where we actually set up the level.
So, what happens is the leveladvancedPanel
fades in and everything nice and does the little animation,
and then while it's just waiting and showing the level,
waiting for the player to read it,
it in the background instantiates all of the different asteroids and stuff.
The reason we do this at that time is because we're
instantiating a bunch of objects and that can cause a performance hit.
But if we're doing a performance hit when we're just showing a static screen anyway,
no one will ever notice.
So, let's take a look at the StartLevel method.
So, here we are looking at the StartLevel method,
where we pass in a level number.
Now first, to makes sure that the LEVEL_LIST is all
set up and that there are levels in the list.
Then it says, "If the number that we passed in is greater than the level list length,
then just go back to the first level."
So, that way, I don't think anyone would get
passed level 10 in this game because it gets really difficult.
But if they do, it just looped back around.
That's now how it would work in a real game.
But that allows the game to keep being played in this prototype that we made.
It sets our game state to pre-level,
sets are level number,
and then pulls the info from the level list.
You'll note that I have a levelNum minus one
because the first level in the list is level one.
So, we do one minus one, gives us zero,
and we get the zeroth element,
which is really like the first element in that list.
Then I clear the asteroids and I clear the bullets,
I will show you those in a second,
and I find objects with the game tag "DestroyWithLevel Change" that's
just another way to make sure that everything gets
destroyed that needs to be destroyed before we change levels.
I set up everything for spawning asteroids and then I spawn the parent asteroids.
That sets up my game.
Now, all of this is happening while
the LevelAdvancePanel is still continuing with this animation.
So, it displayed for awhile and then the next state after display is fadeOut.
You can see the next state is set there on line 118 is fadeOut and then fadeOut,
the next state is fadeOut too,
and it continues to flow through these different elements fading out until finally
the next state on line 152 at the end of the third fadeOut is idle.
When it sets the idle state,
which you can see up here at the top,
then it calls the idleCallback and again sets the idleCallback to null once it's done.
So, that idleCallback is back on Asterax.