Hello again! In this video, we are going to add some more features to our game.
We are going to add some lives, player lives. So the player can win or lose the game.
And we are also going to give some text messages, so we can communicate with the player.
SFML has a text
class. This represents graphical text, which can be drawn on a render target. Such as our game window.
And it also has a font class.
A Text object will have a Font object associated with it, and that will control how the characters
appear on the screen.
This is quite similar to sprites and textures. So we start off by loading the font from disk. And this
can be problematical.
The first problem is that different systems provide different fonts.
So it may be that your system does not actually have this font.
And also different systems keep their fonts in different places.
So the font may be available, but not in the directory where your program expects it.
So if you are going to be distributing your game to other people, then a good thing to do is to copy
the fonts file into the same directory as the images. So your program will be able to find it easily.
And I should add that there are copyright issues with some fonts.
So assuming that you have loaded up your Font objects, you can then associate it with a Text object.
So you call setFont(). And then setString() will populate the Text object with some characters. And then
you can draw the text, and display on the window as usual.
In the game manager,
we are going to add a member for the number of lives the player has.
Each time the ball hits the bottom of the screen, the player is going to lose a life. And if they
lose all their lives, then the game is over and the player has lost.
On the other hand, if the player manages to destroy all the bricks, then they win the game.
We have two more values for the game state enumeration: game over, player losing, and the player
winning.
And we are also going to have some members which are SFML text objects. And those will be used for displaying
messages to the player.
We need to change how the ball reacts, when it hits the bottom of the window.
In the update() member function of ball.
So far, we have been bouncing off the bottom of the window, back into the window. But we do not want to
do that anymore.
We are going to destroy the ball.
So that will make it look as though the ball has disappeared off the bottom of the window.
And then, in the game loop, we can check if the ball has been destroyed.
And that will tell us that the player has lost a life.
In constants, we have a new parameter.
This is the number of lives the player has, at the start of the game. So the player will have three
opportunities to demolish all the bricks.
In the game class,
we have the extra members for the game_state enumeration.
We have the objects for the fonts and the text messages.
text_state will tell the player about the state of the game, and text_lives will tell the player how
many lives they have left.
And we also have a member function which will keep track of how many lives the player has left. And
the initial value will be the total number of lives they have.
So that would be three.
In the game constructor,
we need to initialize these text objects.
So we start off by loading the font. We call loadFromFile().
I chose one which is available on Windows, to make life easier.
If you're using a Unix system or Mac, then the path will look something like that.
webfonts is in fact a package,
I think. This is FreeBSD, so Verdana is not part of the default X installation.
So you could use another font if you want, or just install this one. And then we can configure the objects.
So we set the font to be Verdana.
We search the position, which is going to be near the middle of the screen. And, as usual, this is just
trial and error.
Then we can set the size of the characters and their colour. And then we provide some characters for
the text object. And similar for the text_lives.
And the characters will give the number of lives that the player has left.
So we are using C++11's to_string(), to convert this int to a string.
If we restart the game, then we want the player to have all their lives back.
So we set the lives member back to the maximum.
In the game loop,
we have these extra states. So we need to change the logic slightly. And we also need to display the
text messages.
If the game is paused, then we draw the entities, but we do not update them.
If the game is not running, then we tell the user what the state is.
So this could be paused, game over or player wins.
And I have made these all the same size, with some padding spaces.
And then we draw the text objects on the window.
Otherwise, if the game is running, then we update the entities.
But, before we do that, we need to check some things.
We need to check if the ball has been destroyed.
If it has, then the entity manager will have a vector of ball entities, which is empty.
So we decrement the player lives. And we also create a new ball, so the player can continue playing. And
we set the game state to paused, so the player has some time to recover from their state of shock!
If all the bricks have been destroyed, then the entity manager will have a vector of brick entities
which is empty.
So the player has won.
If the player has no lives left, then they have lost the game.
Then we update the text_lives, so it has the correct number of lives.
And then we do the usual: update manager, handle collision, refresh, draw and display.
So there we are.
We know that the game is paused and we have three lives.
And now I have two lives!
So when the ball goes off the bottom, I lose a life.
(Huh!)
Now I lose another one.
And that is it.
Game over!
(Boo hoo!)
If you want to test the case where the player wins, then you do not have to actually win the game and
destroy all the bricks.
You can take a shortcut.
If you go up to the reset member function, this line here will populate the entity manager's brick vector.
So if we comment this out, then the entity manager will have an empty vector of bricks.
So when we start playing, there are no bricks and the player has won.
One other thing that is worth knowing, and perhaps I should have mentioned earlier. If there is an error
in this loadFromFile() function, so that could be either sprites or fonts, then SFML will print
a message to standard output.
So if you are running in a command line, or your development environment has a console, then you will see
that if you're running in a standalone window like I am, then you will not be able to see that.
So here is how to do this for Visual Studio.
So go into Project Properties, and then Linker, System. And this is controlled by Subsystem.
So currently it is Windows.
If I change this to console, then I will get a console when I start playing the game.
So obviously, that is not something you want when you are releasing your application, but it is useful
for testing and debugging.
For example, if I change this so the load file will fail.
And there we are, we get an error message.
Okay.
So that is it for this video.
So I will see you next time.
But until then, keep coding!