This is part of a series of small projects and tutorials using C++ and SFML
Library version: SFML 3.0.0
C++ Standard: ISO C++20
My Base Project: https://github.com/l-paz91/SFMLProjects/blob/main/main.cpp
In this project, we'll make a simple app that tracks time from when we push a start and stop button. We'll use knowledge gained from the real-time clock project and the mouse tracker. Here's what the finished product will look like:
Step 1 - Displaying Seconds Passed
We need to start off by creating the text object to store the time:
Now, let's make it increase every second. First we need something to store the elapsed time in.
Now we just need to update the elapsed time each frame, calculating the minutes, seconds, milliseconds, and then format them into our preferred string format. Unlike the real-time clock tutorial, I don't want this only updating every second as I want to see the milliseconds updating.
Using the elapsedTime variable, I calculate how much time has passed since the program started. asMilliseconds() returns a 4 digit int, I wanted to display it as 2 digits so I mod by 1000 and then divide by 10. The reasoning for this is, if the total time was say 1 minute, 23 seconds and 456 milliseconds
- elapsedTime.asMilliseconds() would be 83,456
- 83,456 % 1000 gives 456 (just the millisecond portion)
- 456 / 10 gives 45 (showing only the first two digits)
std::setfill() and std::setw() are stream manipulations that control how data is formatted when output to a stream. They're very handy. Setfill() fills characters to whatever you specify (so here it's 0). Setw() sets the width of the field to the number of characters you specify. If a value takes up fewer characters, it will be padded with the fill character from setfill().
They're repeated because steam manipulators only affect the next output operation, they don't persist across multiple insertions to the stream.
Step 2 - Creating a Stop/Start Button
We now have a way of tracking how much time has passed since the program started. But that's not how stopwatches usually work. They start at 0 until you start them, so we need a button to make that happen.
There isn't a button class in SFML. The creators of the library leave those types of implementations up to the developer so they can create their own custom classes. In this tutorial, we'll make something simple that acts like a button using sf::RectangleShape.
The button doesn't do much right now and it doesn't have any text in it. Let's create another text object and render that with the button.
You might've noticed creating text objects is quite repetitive. Again, SFML doesn't abstract further from this though to give us developers freedom to create our own complex classes. At this point you could see how useful a RectangleButton class would be and the kind of things you'd need to do to create that...
Render order is also important in any 3D application. The first object you draw will be the first item that's drawn, allowing you to "draw on top" of other items. This is often referred to as the "z order".
Step 3 - Adding the Stop/Start Logic
Now we've got a button, let's do something when we press it. We know from our Mouse Tracker project that we can get the co-ordinates of the mouse, what if those co-ordinates just so happened to be where our button is and we press the left mouse button? This is basically how we check for our button presses.
With this done, let's have a think about the logic. The app should start with a zeroed timer and only start when we press the button. If the button is pressed again, the timer stops. Press it again, it starts and continues from where it left off. This sounds like we'll need a bool to keep track of whether or not the stopwatch is running.
If you run the app now, nothing happens. Good. So let's flip that bool if LMB is pressed:
If you run the program now:
And that's pretty much a stopwatch at this point. It would be nice if it had a reset button though.
Exercise
Implement a reset button.
If you get stuck: Exercise Solutions. There are many ways to do this; this is just one way of doing it.