In this part of the SFML we will look at creating our first basic SFML application. At the heart of every SFML application is the RenderWindow which provides both a way to draw things on screen and receive input events from the user.
As always, there is an HD video of this tutorial here.
At the heart of every non-trivial game is the game loop. In some game engines it’s hidden away from you inside the engine, but it is always there somewhere. In SFML it is your responsibility to implement, which is what we will do today. A game loop is a pretty simple concept… it’s a loop that runs over and over until your game is completed. Each pass through the loop the screen is cleared and new graphics are drawn (this is referred to as a frame, so when you hear Frames Per Second, this is what is being referred to). There are several other tasks a game is responsible for handling… input and physics to name just two.
Let’s start off with a very simple application:
#include "SFML/Graphics.hpp" int main(int argc, char ** argv) { sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "SFML Demo"); while (true) { renderWindow.clear(); renderWindow.display(); } }
This represents about the simplest meaningful SFML application you can create. We create a new RenderWindow, passing in both its dimensions and title. Then we simply loop forever and each pass through the loop we clear the window then draw it again with a call to display().
When you run this code you will get a black 640×480 window on screen, however if you attempt to move or close this window you will quickly notice something is wrong. It doesn’t respond to any of your actions. In fact, if you lose focus (click on a different window) you can’t even get it to focus again! This is because we aren’t responding to any events. Let’s switch things up a bit so that are window is a tad more responsive. Instead of simply looping forever, we will create a slightly more intelligent game loop.
sf::Event event; while(renderWindow.isOpen()){ // Check for all the events that occured since the last frame. while (renderWindow.pollEvent(event)){ //Handle events here if (event.type == sf::Event::EventType::Closed) renderWindow.close(); } renderWindow.clear(); renderWindow.display(); }
Now your window properly responds to events, it can be moved around and most importantly, it can be closed. Let’s take a quick look at what we’ve done here.
First off, instead of looping forever, we instead loop until our RenderWindow is closed. Next inside this loop we’ve implemented another while loop that calls pollEvent. pollEvent checks for all of the events that occurred since the last time pollEvent was called. It is called inside a while loop because it is possible that multiple events occurred since the last pass through the outer loop. pollEvent() will return false when no more events exist. Events exist for things such as mouse and keyboard actions or the window being resized. In this particular case we are checking to see if the EventType is Closed, which means a close request has occured. In the event that one does we call renderWindow.close() which will result in the next check of isOpen() to return false, thus ending our game.
We will cover events in more detail later, but for an idea of what EventTypes exist, click here. There are two very important things to realize in this game loop. Notice that the sf::Event is declared outside of the loop? This code is going to be called ALOT. Never put variable allocations, even stack based ones like this, inside a high frequency loop if it can be helped. Second, notice how the clear() and display() calls are outside of the inner pollEvent() loop? This is also important, as otherwise your screen with only update when an event occurs!
There is one final important concept to cover before we move on to the next tutorial… time. It is quite common for a game engine to provide the elapsed time since the last frame. This value is very useful to your entire game as we will see shortly. In SFML however you are rolling your own game loop, so you are also rolling your own time tracking system. Don’t worry though, the process is extremely simple. Let’s see one final complete sample that also keeps track of the elapsed time per frame.
#include "SFML/Graphics.hpp" #include <iostream> int main(int argc, char ** argv) { sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "SFML Demo"); sf::Event event; // A Clock starts counting as soon as it's created sf::Clock clock; while(renderWindow.isOpen()){ // Check for all the events that occured since the last frame. while (renderWindow.pollEvent(event)){ //Handle events here if (event.type == sf::Event::EventType::Closed) renderWindow.close(); } // A microsecond is 1/1,000,000th of a second, 1000 microseconds == 1 millisecond std::cout << "Elapsed time since previous frame(microseconds): " << clock.getElapsedTime().asMicroseconds() << std::endl; // Start the countdown over. Think of laps on a stop watch. clock.restart(); renderWindow.clear(); renderWindow.display(); } }
You will notice the addition of an sf::Clock to our game. The Clock provides the most accurate time that the underlying OS is capable of giving (different timers have different resolutions, and this timer needs to be very precise!). As soon as it is declared, it starts counting. Think of sf::Clock like a stopwatch that starts automatically. Each “lap” you can read the elapsed time using getElapsedTime() and you can start a new lap by calling restart(). In this example we get the elapsed time in microseconds. There are 1000 microseconds in a millisecond, and 1000 milliseconds in a second, so a microsecond is one millionth of a second. Like I said, we need precision!
So that is the process of creating a very simple SFML application, clearing and displaying the window, tracking how much time elapsed and handling events. In the next tutorial we will look at events a bit closer and see how best to handle keyboard input.
The Video
Programming SFML CPP Tutorial 2D