As time is a crucial mechanic in the game, it is necessary to keep the player aware of it. He needs to know if his allotted six seconds are about to run out. It will give him a sense of urgency as the end of the game draws near, and a sense of accomplishment if he performs well enough to maintain or increase his remaining time.
Drawing the number of seconds remaining on the screen is not easy to read (when concentrating on the branches) or a particularly interesting way to achieve the objective.
What we need is a time bar. Our time bar will be a simple red rectangle, prominently displayed on the screen. It will start off nice and wide, but rapidly shrink as time runs out. When the player's remaining time reaches zero, the time bar will be gone completely.
At the same time as adding the time bar, we will add the necessary code to keep track of the player's remaining time, as well as to respond when he runs out. Let's go through it a step at a time.
Find the Clock clock;
declaration from earlier and add the highlighted code:
// Variables to control time itself
Clock clock;
// Time bar
RectangleShape timeBar;
float timeBarStartWidth = 400;
float timeBarHeight = 80;
timeBar.setSize(Vector2f(timeBarStartWidth, timeBarHeight));
timeBar.setFillColor(Color::Red);
timeBar.setPosition((1920 / 2) - timeBarStartWidth / 2, 980);
Time gameTimeTotal;
float timeRemaining = 6.0f;
float timeBarWidthPerSecond = timeBarStartWidth / timeRemaining;
// Track whether the game is running
bool paused = true;
First we declare an object of the type RectangleShape
and call it timeBar
. RectangleShape
is an SFML class that is perfect for drawing simple rectangles.
Next we add a few float
variables, timeBarStartWidth
and timeBarHeight
. We initialize them to 400
and 80
respectively. These variables will help us keep track of the size we need to draw the timeBar
each frame.
Next we set the size of the timeBar
using the timeBar.setSize
function. We don't just pass in our two new float
variables. First we create a new object of type Vector2f
. What is different here, however, is that we don't give the new object a name. We simply initialize it with our two float variables and it is passed straight in to the setSize
function.
After that we color the timeBar
red by using the setFillColor
function.
The last thing we do to the timeBar,
in the previous code, is to set its position. The y coordinate is completely straightforward, but the way we set the x coordinate is slightly convoluted. Here is the calculation again:
(1920 / 2) - timeBarStartWidth / 2
The code first divides 1920
by 2
. Then it divides timeBarStartWidth
by 2
. Finally it subtracts the latter from the former.
The result makes the timeBar
sit nice and horizontally centered on the screen.
The final three lines of code that we are talking about declare a new Time
object called gameTimeTotal
, a new float
called timeRemaining
that is initialized to 6
, and a curious-sounding float
named timeBarWidthPerSecond
which we will discuss further.
The timeBarWidthPerSecond
variable is initialized with timeBarStartWidth
divided by timeRemaining
. The result is exactly the amount of pixels that the timeBar
needs to shrink by, each second of the game. This will be useful when we resize the timeBar
in each frame.
Obviously we need to reset the time remaining each time the player starts a new game. The logical place to do this is the
Enter
key press. We can also set the score
back to zero at the same time. Let's do that now by adding this highlighted code:
// Start the game
if (Keyboard::isKeyPressed(Keyboard::Return))
{
paused = false;
// Reset the time and the score
score = 0;
timeRemaining = 5;
}
Now, each frame we must reduce the amount of time remaining and resize the timeBar
accordingly. Add the following highlighted code in the update section as shown here:
/*
****************************************
Update the scene
****************************************
*/
if (!paused)
{
// Measure time
Time dt = clock.restart();
// Subtract from the amount of time remaining
timeRemaining -= dt.asSeconds();
// size up the time bar
timeBar.setSize(Vector2f(timeBarWidthPerSecond *
timeRemaining, timeBarHeight));
// Set up the bee
if (!beeActive)
{
// How fast is the bee
srand((int)time(0) * 10);
beeSpeed = (rand() % 200) + 200;
// How high is the bee
srand((int)time(0) * 10);
float height = (rand() % 1350) + 500;
spriteBee.setPosition(2000, height);
beeActive = true;
}
else
// Move the bee
First we subtracted the amount of time the player has left by however long the previous frame took to execute with this code:
timeRemaining -= dt.asSeconds();
Then we adjusted the size of the timeBar
with the following code:
timeBar.setSize(Vector2f(timeBarWidthPerSecond * timeRemaining, timeBarHeight));
The x value of the Vector2F
is initialized with timebarWidthPerSecond
multiplied by timeRemaining
. This produces exactly the correct width, relative to how long the player has left. The height remains the same and timeBarHeight
is used without any manipulation.
And, of course, we must detect when time has run out. For now, we will simply detect that time has run out, pause the game, and change the text of the messageText
. Later we will do more work here. Add the highlighted code right after the previous code we added, and we will look at it in more detail:
// Measure time
Time dt = clock.restart();
// Subtract from the amount of time remaining
timeRemaining -= dt.asSeconds();
// resize up the time bar
timeBar.setSize(Vector2f(timeBarWidthPerSecond *
timeRemaining, timeBarHeight));
if (timeRemaining <= 0.0f)
{
// Pause the game
paused = true;
// Change the message shown to the player
messageText.setString("Out of time!!");
//Reposition the text based on its new size
FloatRect textRect = messageText.getLocalBounds();
messageText.setOrigin(textRect.left +
textRect.width / 2.0f,
textRect.top +
textRect.height / 2.0f);
messageText.setPosition(1920 / 2.0f, 1080 / 2.0f);
}
// Set up the bee
if (!beeActive)
{
// How fast is the bee
srand((int)time(0) * 10);
beeSpeed = (rand() % 200) + 200;
// How high is the bee
srand((int)time(0) * 10);
float height = (rand() % 1350) + 500;
spriteBee.setPosition(2000, height);
beeActive = true;
}
else
// Move the bee
Stepping through the previous code:
if(timeRemaining <= 0.0f)
paused
to true
so this will be the last time the update part of our code is executed (until the player presses
Enter
again).messageText
, calculate its new center to set it as its origin, and position it in the center of the screen.Finally, for this part of the code, we need to draw the timeBar
. There is nothing new in this code that we haven't seen many times before. Just note that we draw the timeBar
after the tree, so it is visible. Add the highlighted code to draw the time bar:
// Draw the score
window.draw(scoreText);
// Draw the timebar
window.draw(timeBar);
if (paused)
{
// Draw our message
window.draw(messageText);
}
// Show everything we just drew
window.display();
Now you can run the game. Press Enter to start, and watch the time bar smoothly disappear down to nothing.
The game then pauses and the OUT OF TIME!! message will appear.
You can, of course, press Enter again to start the whole thing running from the start.
3.131.38.14