- [Instructor] Hi, this video is
Building the levelManager Class.
In the previous video, we learned about designing levels.
In this video, we're going to code LevelManager.h
and LevelManager.cpp.
It will take several phases of coding
to make our level designs work.
The first thing we will do
is code the LevelManager header file.
This will allow us to look at and discuss
the member variables and functions
that will be in the LevelManager Class.
Next, we will code the LevelManager.cpp file
which will have all the function definitions in it.
As this is a long file, we will break it up
into several sections to code and discuss them.
Once the LevelManager Class is complete,
we will add an instance of it
to the game engine, Engine Class.
We will also add a new function
to the Engine Class loadLevel which we can call
from the update function whenever a new level is required.
The loadLevel function will not only
use the LevelManager instance to load the appropriate level,
but it will also take care of aspects
such as spawning the player characters
and preparing the clock.
As already mentioned, let's get an overview
of LevelManager by coding the LevelManager.h file.
Create a .h file is always right click header files
in the solution explorer and select add new item.
Click headerfile.h, and then, in the name field,
type LevelManager.
Lastly, click Add.
We are now ready to code the header file
for the LevelManager Class.
Now add this highlighted code to the file.
It consists of necessary include directives
and private variables.
Here we're adding an include directive
called SFML Graphics.hpp.
Then, we are using namespace sf and namespace std.
In the LevelManager Class,
these are the various private variables.
The code first declares Vector2im_LevelSize
to hold two integer values that will hold the horizontal
and vertical number of tiles that the current map contains.
Vector2fm_StartPosition contains the coordinates
in the world where Bob and Thomas should be spawned.
Note that this is not a tile position relatable
to m_LevelSize units,
but a horizontal and vertical pixel position in the level.
The m_TimeModifier member variable is a float
that will be used to multiply the time available
in the current level.
The reason we want to do this is so that by changing,
decreasing this value
we will shorten the time available each time
the player attempts the same level.
As an example, if the player gets 60 seconds
for the first time they attempt level one
then, 60 multiplied by one is of course 60.
When the player completes all the levels
and comes back to level one for the second time,
m_TimeModifier will have been reduced by 10%.
Then, when the time available is multiplied by 0.9,
the amount of time available to the player
will be 54 seconds.
This is 10% less than 60.
The game will get steadily harder.
The float variable m_Base time limit holds the original
unmodified time limit we have just been discussing.
You can probably guess that m_CurrentLevel
will hold the current level number that is being played.
The int NUM_Levels constant will be used to flag
when it is appropriate to go back to level one again
and reduce the value of m_TimeModifier.
Next, add this highlighted code
which consists public variables and function declarations.
Let's go through it.
Notice that there are two constant int members.
TILE_size is a useful constant to remind us
that each tile in the sprite sheet
is 50 pixels wide and 50 pixels high.
VERTS_IN_QUAD is a useful constant
to make our manipulation of a vertex array
less error prone.
There are, in fact, four vertices in a quad.
Now we can't forget it.
The get TimeLimit, get StartPosition, get LevelSize,
and get CurrentLevel functions are simple getter functions
that return the current value
of the private member variables
we declared in the previous block of code.
A function that deserves a closer look is nextLevel.
This function receives a vertex array reference
just like we use in the Zombie Arena game.
The function can then work on the vertex array
and all the changes will be present
in the vertex array from the calling code.
The next level function returns a pointer to a pointer
which means we can return an address
that is the first segment
of a two dimensional array of int values.
We will be building a two dimensional array
of int values that will represent the layout of each level.
Of course, these int values will be read
from the level designed text files.
Now we'll code the LevelManager.cpp file.
Right click Source Files in the solution explorer,
and select add new item.
In the add new item window, select C++ file,
and then rename the file to LevelManager.
Lastly, click Add.
We are now ready to code the .cpp file
for the LevelManager Class.
As this is quite a long class, we'll break it up
to discuss it in six chunks.
The first five will cover the nextLevel function,
and the sixth all the rest.
Add this highlighted code.
Here we are adding Shows Include Directives,
and the first of five part of the nextLevel function.
After the include directives,
the code initializes m_LevelSize.x and
m_LevelSIze.y to zero.
Next, m_CurrentLevel is incremented.
The if statement that follows checks
whether m_CurrentLevel is greater than NUM_Levels.
If it is, m_CurrentLevel is sent back to zero,
and m_TimeModifier is reduced by 0.1f
in order to shorten the time allowed for all levels.
The code then switches based on the value held by
m_CurrentLevel.
Each case statement initializes the name of the text file
which holds the level design.
And the starting position for Thomas and Bob,
as well as m_BaseTimeLimit
which is the unmodified time limit
for the level in question.
Now add the second part of the nextLevel function.
Add this highlighted code
immediately after the previous code.
We'll go through it in detail.
First, we declare an if stream object called input file
which opens a stream to the file name
contained in leveltoLoad.
The code loops through each line of the file
using get line, but doesn't record any of its content.
All it does is count the number of lines by incrementing
m_LevelSize.y.
After the while loop, the width of the level
is saved in m_LevelSize.x using s.length.
This implies that the level length of all the lines
must be the same or we would run into trouble.
At this point, we know and have saved
the length and width of the current level
in m_LevelSize.
Now add the third part of the next level function.
Add this code immediately after the previous code.
Here, we first, we clear Input file
using its clear function.
The seek g function called with the zero ios beg parameters
resets the string back to before the first character.
Next, we declare a pointer to a pointer called arrayLevel.
Note that this is done on the free store or heap
using the new key word.
Once we have initialized this two dimensional array,
we'll be able to return its address to the calling code,
and it will persist until we either delete it
or the game is closed.
This is for loop loops from zero to m-LevelSize.y minus one.
In each pass, it adds a new array of int values
to the heap to match the value of m_LevelSize.x.
We now have a perfectly configured for the current level
two dimensional array.
The only problem is that there's nothing in it.
Next, we add the fourth part of the nextLevel function.
Add this code immediately after the previous code.
First, the code initializes a string called row
which will hold one row of the level design at the time.
We also declare and initialize and int called y
that will help us count the rows.
The while loop executes repeatedly until input file
gets past the last row.
Inside the while loop, there is a for loop
which goes through each character of the current row
and stores it in the two dimensional array, arrayLevel.
Notice that we assess exactly the right element
of the two dimensional array
with arrayLevel, array of y, and x.
The a to i function converts char val to int.
This is what is required because we have
a two dimensional array for int not char.
Over here, we increment y and lastly close the file.
Now add the fifth part of the nextLevel function.
Add the code right after the previous one.
This is entire highlighted code.
Just after close the file.
Although this is the longest section of code
from the five sections we divided nextLevel into,
it is also the most straight forward.
What happens is that the nested for loop loops
from zero through to the width and height of the level.
For each position in the array, four vertices are
put into vertex array and for text coordinates
are assigned from the sprite sheet.
The positions of the vertices and texture coordinates
are calculated using the current vertex available
the tile size and VERTS_IN_QUAD constants.
At the end of each loop of the inner for loop,
current vertex is increased by VERTS_IN_QUAD
moving nicely onto the next tile.
The important thing to remember about this vertex array
is that it was passed into nextLevel by reference
therefore the vertex array will be available
in the calling code.
We will call nextLevel from the code in the Engine Class.
Once this function has been called,
the Engine Class will have a vertex array
to represent the level graphically.
A two dimensional array of int values
as a numerical representation of all the platforms
and obstacles in the level.
The last part is remaining now.
You have to add this highlighted code after the end
of nextLevel function.
Here we are adding rest of the functions
from LevelManager Class.
These LevelManager functions are all simple getter functions
but do take the time to familiarize yourself
with what private value is returned by which function.
Now that the LevelManager Class is complete
we can move on to using it.
We will code another function in the Engine Class to do so.
Cool!
In this video, we have learned
building the LevelManager Class.
Next up, we'll code the loadLevel function.