Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
15. October 2015

 

In the previous tutorials we covered configuration, game loop and finally keyboard handling.  Today we are going to move on to the basics of graphics programming in SFML.  We are going to start with simple geographic primitives, then in the following tutorial we will move on to sprites.  You will notice right away that SFML is remarkably consistent in it’s approach to graphics, just like it is with Events.

 

As always, there is an HD video of this tutorial available here.

 

Let’s jump right in with a simple example that draws a blue circle on the screen.

// Demonstrate primitve drawing in SFML

#include "SFML/Graphics.hpp"

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;

  sf::CircleShape circleShape(200);
  circleShape.setFillColor(sf::Color::Blue);

  while (renderWindow.isOpen()){
    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
        renderWindow.close();
    }

    renderWindow.clear();
    renderWindow.draw(circleShape);
    renderWindow.display();
  }


}

Run this code and you will see:

image

This example creates a circle with a radius of 200 pixels that is filled with the colour blue.  Drawing is simply a matter of passing the shape into the draw() method of RenderWindow.  This is the way you draw pretty much everything in SFML.  If you take a look at the class reference for Drawable, the base class of any object passed into draw(), you can get a good idea of what classes are available.

image

 

As you can see, our CircleShape is part of that hierarchy.   Other than showing how to draw things to a window, this example shows us a few key concepts.  First, notice that we didn’t specify the location of our circle and by default it drew itself at the top left corner of the screen?  This shows us two critical things.  First, that the origin (0,0) of a window in SFML is the top left corner.  Second, that the origin/pivot ( the point within a shape a Drawable is drawn relative to ) is also it’s top left corner.  What if for example we wanted to position our circle relative to it’s midpoint instead?  Fortunately this is quite simple:

  sf::CircleShape circleShape(200);
  circleShape.setOrigin(circleShape.getRadius(), circleShape.getRadius());
  // or you could have calculated the mid point like so:
  // circleShape.setOrigin(circleShape.getLocalBounds().width / 2.0f, circleShape.getLocalBounds().height / 2.0f);

  circleShape.setFillColor(sf::Color::Blue);

Here we are setting the point draw calls are performed relative to by calling setOrigin().  This call sets that point in pixel coordinates relative to the top left corner of the Drawable.  Now this code will result in the following:

image

One other concept we didn’t cover is actually positioning our objects.  It is simply a matter of calling setPosition() like so:

circleShape.setPosition(100.0f, 100.0f);

This will result in the shape being drawn 100 pixels right and 100 pixels down from the top left corner of the window.  Of course the origin value is going to influence how that draw is performed.

 

Another important concept to cover is draw order.  Let’s throw in another circle, this time a red one, to illustrate what I mean:

    sf::CircleShape circleShape(200);
    circleShape.setFillColor(sf::Color::Blue);
    circleShape.setPosition(100.0f, 100.0f);

    sf::CircleShape circleShape2(200);
    circleShape2.setPosition(0.0f,0.0f);
    circleShape2.setFillColor(sf::Color::Red);
  
    //snip

    renderWindow.clear();
    renderWindow.draw(circleShape);
    renderWindow.draw(circleShape2);
    renderWindow.display();
  

 

Now run it and:

image

 

The order of draw calls is critically important.  Swap around the code, like so:

    renderWindow.clear();
    renderWindow.draw(circleShape2);
    renderWindow.draw(circleShape);
    renderWindow.display();

And you get:

image

 

As you can see, the later the draw call, the higher the z order.  Or put simply, things draw first are drawn first, then subsequent draw calls are drawn over top.  For future reference, this order is often referred to as the z-index.

 

Now that we have graphics to play with, there are a few things we can do with them…  such as move, rotate and scale.  Each of those functions transforms relative to the current position.  You can also directly set all three values using setPosition, setRotation and setScale.  With shapes, you also have control over the contour or line that composes the shape, like so:

  sf::CircleShape circleShape(200);
  circleShape.setFillColor(sf::Color::Blue);
  circleShape.setPosition(50.0f, 50.0f);
  circleShape.setOutlineThickness(10);
  circleShape.setOutlineColor(sf::Color::Green);

Here we set the line width to 10pixels and the color to green, resulting in:

image

 

As you may have noticed from the inheritance diagram earlier, there exist other shapes, ConvexShape and RectangleShape.  RectangleShape should be pretty self explanatory, bull ConvexShape requires a touch of explanation.  The Convex shape represents a convex hull, which is to say a closed shape of lines that never intersect or exceed 180 degrees.  You define a ConvexShape as a series of points, but it is important that you draw your shape in either a clockwise or counter-clockwise order so SFML knows how to draw it.  Here is an example creating a ConvexShape:

  sf::ConvexShape convexShape;
  convexShape.setPointCount(5);
  convexShape.setFillColor(sf::Color(147, 112, 227)); // PURPLE!
  convexShape.setOutlineThickness(3.0f);
  convexShape.setOutlineColor(sf::Color::White);
  convexShape.setPoint(0, sf::Vector2f(0.0f, 0.0f));
  convexShape.setPoint(1, sf::Vector2f(renderWindow.getSize().x, 0.0f));
  convexShape.setPoint(2, sf::Vector2f(renderWindow.getSize().x, renderWindow.getSize().y));
  convexShape.setPoint(3, sf::Vector2f(renderWindow.getSize().x / 2, renderWindow.getSize().y / 2));
  convexShape.setPoint(4, sf::Vector2f(0, renderWindow.getSize().y));


Resulting in

image

 

That’s it for basic graphics and shape rendering.  In the next tutorial we will expand upon this graphics knowledge and start looking at using sprites.

 

The Video

 

Programming


12. October 2015

 

In our prior tutorial we created a simple application that showed the basics of event handling in SFML.  In this tutorial we are going to expand upon that concept a bit further and show how to read the keyboard, both using events and direct polling.  Although not strictly SFML related (anymore anyways), we are also going to be covering random number generators as part of our demonstration, a very common task in game development.

 

As always, there is an HD video version of this tutorial.

 

Earlier we used the RenderWindow method pollEvent() to check for and respond to the Closed event.  Now let’s look at the process of responding to keyboard events.

while (renderWindow.pollEvent(event)){
    //Handle events here
    if (event.type == sf::Event::EventType::Closed)
      renderWindow.close();

    //Respond to key pressed events
    if (event.type == sf::Event::EventType::KeyPressed){
      if (event.key.code == sf::Keyboard::Space){
        // Do something here
      }
    }
  }

 

As we can see, responding to a KeyPressed event is nearly identical to a Closed event.  The key difference is, once you have identified that the event is a keyboard event you have additional information available in the event’s key structure.  The value of key.code is a sf::Keyboard::Key enum for each available key.  In addition to the KeyPressed event, there is also a KeyReleased event that is sent when the key is, well, released.  By default KeyPressed will be fired again and again if held down.  If you would prefer to have only a single event fired for a key press you can change this behaviour using the RenderWindow setKeyRepeatEnabled().

 

This is an example of Event driven programming in which your program responds to events as they occurred.  Sometimes however you would rather poll for input then wait for it to occur.  For example you might want to ask “hey computer, what keys are pressed?” or “is the control key down?”.  Fortunately SFML supports this out of the box, like so:

  if (sf::Keyboard::isKeyPressed(sf::Keyboard::R))
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) || sf::Keyboard::isKeyPressed(sf::Keyboard::RControl))
      // Do something

 

This code snippet first checks if the ‘R’ key is currently pressed.  It then checks to see if the Control key is pressed, as you can see in the example above the left and right control keys are separate events.  You can mix and match event driven and polled input handling however you want, but be careful not to get in a situation where you are accidentally handling the same input multiple times.

 

We are going to create a full example in a second that puts all of these processes together by randomly changing the screen color based on keys being pressed.  First, lets cover that process of creating a random number, a very common process in game development.  In fact, random number generation used to be part of SFML, but as of SFML 2.0 it was removed, partly because it didn’t make sense and partly because it’s now well entrenched in the language in a cross platform manner.

 

There are two ways we can generate random numbers, using the older C style, or the more modern C++ 11 style.  The new way is more appropriate for generating truly random numbers for security reasons and has no global state, but the old C style way should be more than sufficient for game development, so pick the way you like best.  The process is very similar… you generate a sequence of random numbers using some form of seed value, then massage the results into the numeric range you want.  Let’s look first at the C way of generating randoms:

  srand(time(NULL));               //seed random number generator with the current time
  auto randomNumber = rand() % 255;//generate a random number then confine it to a value of 0-255.

The first call sends the random number generator using the current system time.  Then we call rand() to get a random number.  One important thing to be wary off, the seeding process is fairly slow, while the rand() call is slightly lighter weight.  Next we look at the C++ way:

  std::uniform_int_distribution<int> randomColorRange(0, 255);
  std::random_device rd;
  std::mt19937 randomNumbers(rd());
  auto randomVal = randomColorRange(randomNumbers);

This example does basically the same thing as the earlier version.  The uniform_int_distribution object is a lightweight object that can be used to massage the data generated by mt19937 algorithm into actual int values within the defined range.  The mt19937 is an implementation of Mersenne Twister algorithm for generating random numbers.  The random_device is a built in object for creating a seed for your random number generator instead of using the current time ( although it’s quite possible that random_device uses the time behind the scenes ).  Using random_device is heavy weight, as is mt19937, so be careful where you generate random numbers.  However using those generated numbers with a uniform_int_distribution is light weight.

 

Ok, so we now know how to respond to keyboard events, poll the keyboard directly and generate random numbers, let’s tie it all together in a single example.

// This example demostrates the main loop

#include "SFML/Graphics.hpp"
#include <iostream>
#include <random>

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::Color color(sf::Color::Red);


  // C++ 11 way of generating a random between 0 - 255
  // mt19937 is an implementation of the Mersenne Twister pseudo random number generator
  // random_device() returns a random number to use as a seed for the mt algorithm... slow however so that's why we dont just use it for all randoms if you were wondering
  // mt results arent in a human friendly format, so we use uniform_int_distribution to "shape" the results to our range and type
  // uniform_int_distribution is a fairly "light" object.  random_device and mt19937 aren't.
  std::uniform_int_distribution<int> randomColorRange(0, 255);
  std::random_device rd;
  std::mt19937 randomNumbers(rd());
  
  // Pre-C++ 11 but more common way (*with issues, see:
  //https://www.reddit.com/r/programming/comments/1rnudl/quite_interesting_why_cs_rand_is_considered/
  // Mostly doesn't apply to game devs if not using rand for say... security.
  
  /*
  srand(time(NULL));          //seed random number generator with the current time
  auto randomNumber = rand() % 255;   //generate a random number then confine it to a value of 0 - 255.
  */

  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();

      //Respond to key pressed events
      if (event.type == sf::Event::EventType::KeyPressed){
        if (event.key.code == sf::Keyboard::Space){
          color.r = randomColorRange(randomNumbers);
        }
      }
    }

                      
    // Now demonstrate input via polling
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::R))
      if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) || sf::Keyboard::isKeyPressed(sf::Keyboard::RControl))
        color.r = 0;
      else
        color.r = randomColorRange(randomNumbers);

    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::G))
      if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) || sf::Keyboard::isKeyPressed(sf::Keyboard::RControl))
        color.g = 0;
      else
        color.g = randomColorRange(randomNumbers);
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::B))
      if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) || sf::Keyboard::isKeyPressed(sf::Keyboard::RControl))
        color.b = 0;
      else
        color.b = randomColorRange(randomNumbers);

    

    renderWindow.clear(color);
    renderWindow.display();
  }

}

 

All we are doing in this example is setting the clear color of the RenderWindow based on keyboard input.  On pressing the spacebar we handle this using event driven input and set the Red channel of our clear color to a random value between 0-255.  A value of 0 means no red, while 255 is fully red.  We then directly poll the keyboard for input look to see if the R/G/B keys are pressed.  If they are, we assign that color channel to a random value.  If we also have the control key pressed, we instead set that channel to 0.  Therefore pressing CTRL+R, CTRL+G, CTRL+B will result in a black window.

 

As you can see, SFML makes it simple to handle keyboard input, both using an event driven model or by polling.  One thing it does not provide however is any sense of history.  We can check if a key was pressed or released during a given frame but we can’t really track the history a very common requirement.  That said, rolling your own solution is very simple, as shown below:

// This example demostrates the main loop

#include "SFML/Graphics.hpp"
#include <unordered_map>
#include <iostream>

int main(int argc, char ** argv) {
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "SFML Demo");

  sf::Event event;

  // If true, you will continue to receive keyboard events when a key is held down
  // If false, it will only fire one event per press until released
  renderWindow.setKeyRepeatEnabled(false);

  std::unordered_map<int, bool> keys;
  std::list<int> changedKeys;

  while (renderWindow.isOpen()){
    changedKeys.clear();

    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
        renderWindow.close();

      if (event.type == sf::Event::EventType::KeyPressed){
        if (keys.count(event.key.code) == 0){
          keys[event.key.code] = true;
          changedKeys.push_back(event.key.code);
        }
      }
      if (event.type == sf::Event::EventType::KeyReleased){
        if (keys.count(event.key.code) == 1){
          keys.erase(event.key.code);
          changedKeys.push_back(event.key.code);
        }
      }
    }

    std::cout << "Currently pressed keys: ";

    // To get the actual value as a string, you need to use Thor or write your own version
    for (auto& keyValue : keys)
      std::cout << keyValue.first << " ";
    std::cout << std::endl;

    if (!changedKeys.empty()){
      std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Keys changed" << std::endl;
    }
    renderWindow.clear();
    renderWindow.display();
  }

}


This approach is pretty typical of SFML.  The basic tools are there for you, but you may have to build a layer on top to fit your game.  That said, there is a library called Thor that covers many of these common scenarios, essentially a utility library built over top of SFML providing additional functionality.  For example, in addition to providing the kind of functionality we just implemented above, there is also a utility for turning SFML Key enum values into a printable format.  We will probably cover using at least parts of Thor at a later point in this series, but for now I want to focus on core SFML.

 

The Video


Programming


9. October 2015

 

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 640x480 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.  That’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


7. October 2015

 

This text tutorial is a companion to this video tutorial showing how to create and configure a new SFML project using Visual C++ 2013.  If you are running Visual Studio 2015 instead, the process should be virtually 100% identical, although you will have to download a different set of files.

 

First you need to download a version of SFML.  Head on over to the SFML download page and select the newest SFML version, as of writing 2.3.2:

image 

 

Now you need to figure out which version to download.  This mostly comes down to identifying what C++ compiler you are using as well as the “bit-ness” you want to target.  Keep in mind, even though you OS is 64bit, it is likely that you want to use the 32bit version.  This is especially true if your game is meant to run on Windows XP.  A 32bit binary can run on a 64bit OS, but not the opposite.  Additionally, for a 2D game, 64bit doesn’t really get you all that much in return.  In the end though, it doesn’t really matter which one you choose, just be aware of the results.

image

 

Now that we have SFML downloaded, extract the resulting zip file somewhere.

 

Now load up Visual Studio and create a new C++ project of type Win32 Console Application:

image

Name it and locate it however you want then click ok.

 

A new window will pop up, click next, then on the next screen, I used the following settings:

image

Click Finish.

 

We now have a project, let’s add a bit of code to it.   In solution explorer, right click your the Source Files folder in your project and choose Add->New Item..

image

 

Now choose C++ file and name it Main.cpp.

image

 

Click Add and your file is created.

 

Now enter the following code:

#include "SFML/Graphics.hpp"


int main(int argc, char** argv)
{
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Hello SFML");
  while (true){
    renderWindow.clear();
    renderWindow.display();
  }
}

 

You will notice lots of errors in Visual Studio, like so:

image

Don’t worry, we will fix these in a second.

 

Copying files from SFML

Open up the archive you downloaded earlier from sfml.  The contents should look something like this:

image

Copy the folders include and lib to your project directory, which should now look something like this:

image

 

Leave the SFML folder open, we will need it again in a second.

 

Configuring Visual Studio

 

Now that we have the libraries and header files copied into our project, we need to tell Visual Studio about them.  Right click your project and select Properties:

image

 

In the resulting dialog, select C++ on the left, then Additional Include Directories:

image

 

Enter the following value (for more detailed explanations, watch the video, it goes more into the why of things):

image

Make sure to hit enter and it goes bold so you know your setting was saved.

 

Now we need to configure the linker.  On the left hand side select Linker instead of C++ then Additional Library Directories:

image

 

Now enter the following:

image

 

Next we need to add our lib files.  Under linker, select Input, then locate Additional Dependencies on the right.

image

 

Assuming you are using all of the components of SFML and linking to DLLs ( see video for more options ), click in the white area and select edit and add the following (order is important!):

image

 

Your project should now be configured.  Hit CTRL+SHIFT+B to build it.  Don’t run it yet, it wont work without the DLLs, but we need to build it once to have the proper folders made.  Assuming your build went without errors, you should now have a Debug folder inside your project directory, like so:

image

 

Now, remember the SFML zip file I told you to keep open?  Switch back to it and select the contents of the bin folder:

image

And paste them into your Debug directory.  This folder actually contains both debug and release dlls, and you only need the debug for now, but disk space is cheap, no? :)  We will cover building for release at a later date and I will go into the difference in more details then.

 

Now your “game” should be ready to run, hit F5:

image

 

Congratulations, you just completed your first successful SFML project.  Now let’s head over to the next tutorial and make it actually do something!

 

The Video

 

Programming


14. September 2015

 

In this Closer Look At we are going to be taking a closer look at the SFML framework.  The Closer Look At series is a combination of an introduction, overview and getting started tutorial that is designed to help you quickly decide if a game engine/framework/library is right for you.  SFML stands for Simple and Fast Multimedia Library.  It’s a cross platform, open source, C++ based collection of libraries handling 2D graphics, input, audio and networking.

sfmlBanner

 

An HD video of this guide is available here or embedded below.

 

Meet SFML

 

SFML itself is not technically a game engine, it contains no concept of a scene graph, there are no tools, no level editor, etc.  Instead it provides the base technical building blocks your build your game or game engine on top of, including platform agnostic system classes, input, audio, networking and 2D graphics.  The library itself is very modular in nature and you only use what you need.  In terms of scope and functionality it is very similar to LWJGL, Allegro or SDL. 

 

SFML is written in C++ and the source is hosted in this Github repository.  It uses the cross platform CMake build system enabling you to create project files for your platform and IDE of choice.  There are language bindings available for many other languages including:

  • C
  • .NET (C#, VB.Net, F#, Managed C++, etc.)
  • D
  • Java
  • Python
  • Ruby
  • Rust

The full selection of language bindings is available here.  Note however, on the C and .NET bindings are officially supported, the rest are developed or contributed by the community and may be incomplete or lag behind the current release.

 

SFML is composed of several modules, available in static and dynamic forms and compiled in debug or release format.  The modules are:

  • system handles system level tasks in a cross platform manner, items such as threading, timers and strings
  • window native window handling, as well as input handling (polled and event driven mouse, keyboard, touch and gamepads)
  • graphics 2D graphics, sprites, textures, shapes, etc.  built over OpenGL
  • audio audio playback and recording as well as positional audio
  • network TCP and UDP based networking as well as FTP and HTTP implementations

 

Your application or game has to always include the system module as all the other modules depend on it, but all others can be used independently.  For example, if you wanted to use SFML for gamepad support, you could simply link system and window.  It is actually quite common to use SFML in place of libraries like GLut for handling window creation and input handling in a OpenGL 3D application, ignoring the graphics, audio and networking functionality available.  It should be made clear SFML is not and never will be a 3D library, although it can be used in conjunction with 3D libraries and is built over OpenGL.

 

SFML has traditionally been for desktop operating systems only, which I believe hindered it’s adoption to a degree.  However as of version 2.2, there has been support for Android and iOS targets as well.

 

Developing with SFML

 

Since SFML is a code only solution, I suppose it makes sense to jump right in with the coding experience eh?  Installation is a breeze, assuming your compiler is supported out of the box and you have experience setting up a C++ project.  Configuring the linker, working directory, etc.  are all huge potential tripping points for new developers.  I walk through the entire process for Visual Studio 2013 in the video if you need help.  If your compiler isn’t supported out of the box, you will have to build it from scratch using CMake.  I actually documented this process in the past, on both Windows and MacOS with CLion if you want more information.

 

Ideally though, you will just use the precompiled binaries available here(2.3.1 link).  Simply select the combination that is right for you.  If in doubt and running on Windows, select the 32bit version.

image

 

Simply extract the libraries and configure your IDE or makefile to point to the include and lib files, while the required DLLs are in the bin directory and need to be copied into your application folder or somewhere on your system’s path.  This process is beyond the scope of this guide, so if you want more details be sure to watch the video.    There are however getting started tutorials for Windows, Code Blocks, Linux, XCode/Mac and using CMake.  The Windows tutorial is solid, although has a few problems that could trip up new users.  ( No mention of requiring the DLLs for a dynamic build, while defining the process for static linking, but not actually setting up the appropriate libraries ).  Frankly if you are new and are going to have trouble with SFML, this is probably the point that it will happen.  It’s not really SFML’s fault, the downside of using a language with a compile/link process from the 1970s.

 

Now let’s an extremely simple SFML application.

#include "SFML/Graphics.hpp"

int main(int argc, char** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Hello Cruel World");

  while (renderWindow.isOpen()){
    sf::Event event;

    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
        {
          renderWindow.close();
        }
      }
      renderWindow.clear(sf::Color::White);
      renderWindow.display();
    }
  }
}

 

This is about the simplest SFML application you can create and for good reason, it does almost exactly nothing!  When you run it, it simply creates a main window 640x480 in size, like so;

image

 

It does however show you the very basics of a typical SFML game loop.  The application starts up, creates a RenderWindow object, then loops forever or until that window is closed.  Each pass through the loop it checks to see all the events that have occurred since that last pass through the loop.  Finally it clears the screen and renders the results.  If you’ve ever seen a game loop before, this should look immediately familiar.

 

Now let’s change things up a bit so it actually does something useful.  I think it’s about time for a Hello World example!

#include <iostream>
#include "SFML/Graphics.hpp"


int main(int argc, char** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Hello Cruel World");

  // Create a font object and load it from file relative
  sf::Font font;
  if (!font.loadFromFile("calibri.ttf")){
    return 42; // Robust error handling!
  }
  
  //Create Hello World text objecct using our font and size 128pt
  sf::Text text("Hello World", font, 128);

  //Set the text color to red 
  text.setColor(sf::Color::Red);

  //Get the text object's physical dimensions and use them to center the text to 
  our render window
  //By default things are drawn relative to their top left corner and can be 
  changed by calling setOrigin()
  sf::FloatRect bounds(text.getLocalBounds());
  text.setPosition(renderWindow.getSize().x/2 - (bounds.left + bounds.width/2), 
          renderWindow.getSize().y/2 - (bounds.top + bounds.height/2));

  while (renderWindow.isOpen()){
    sf::Event event;

    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
      {
        renderWindow.close();
      }
    } 
    renderWindow.clear(sf::Color::White);
    //Draw our text object to the window
    renderWindow.draw(text);
    renderWindow.display();

  }
}

 

In this example we draw the text Hello World centered to our screen in red.

image

 

The code is fairly extensively commented but gives you a better idea of how things work in SFML.  One thing to be aware of, I had to copy the ttf into the working directory.  If the font fails to load, it most likely isn't in the correct place.  By default the origin (0,0) is the top left corner, both of the window and of the object, but can be changed if you prefer.

 

This example shows two key concepts in SFML, resource loading and Drawables.  The Font resource is loaded using it’s method loadFromFile(), although other options exist for loading.  These calls are expensive and the resulting object is heavy, meaning you should be careful in where you do it and how long you keep the resource around.  The sf::Text object on the other hand is rather light weight, using far less resources.  It is possible to share a single sf::Font with multiple sf::Text objects. 

 

The other thing of note here is the sf::Text class which derives from two key classes, sf::Drawable and sf::Transformable.  The one class gives the Text object the ability to be drawn to the RenderWindow, while the Transformable class gives it spatial properties, enabling the option to be transformed and positioned.  These two classes are inherited by several key objects in SFML including sf::Text, sf::Shape and sf::Sprite.

 

Speaking of Sprite’s, let take a look at loading and displaying graphics as well as handling input in our next example:

#include "SFML/Graphics.hpp"


int main(int argc, char** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Hello Cruel World");
  sf::Texture texture;
  if (!texture.loadFromFile("GFSLogo.png")){
    renderWindow.close();
  }

  sf::Sprite sprite(texture);
  sprite.setPosition(0, 0);

  while (renderWindow.isOpen()){
    sf::Event event;

    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
      {
        renderWindow.close();
      }

      if (event.type == sf::Event::EventType::KeyPressed)
      {
        // Event driven input handling
        if (event.key.code == sf::Keyboard::Left)
          sprite.move(-1, 0); //Relative transform
        if (event.key.code == sf::Keyboard::Right)
          sprite.move(1, 0);
      }
    } 
      // Polled input handling -- mouse coordinates are in screen space, not 
      window space
      if(sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
        sprite.setPosition(static_cast<sf::Vector2f>(sf::Mouse::getPosition(
                           renderWindow)));//Absolute transform

      renderWindow.clear(sf::Color::White);
      renderWindow.draw(sprite);
      renderWindow.display();

  }
}

 

When you run this example you see your image on screen, like so:

image

 

You can move the image left and right one pixel at a time using the left and right arrow keys.  If you hold down the spacebar the image will move along with the mouse cursor.

 

As you can tell, the functionality between using sf::Text and sf::Sprite are very similar and follow a similar pattern.  The Resource itself ( the Font in the earlier example, the Texture in this example ) are heavy weight objects and loaded at start up.  The instance though, in this case the Sprite, is a much lighter weight object that uses the resource.  Due to the common parent’s, the code looks virtually identical between the two objects.

 

Here you also see the two ways you can handle input in SFML.  Can handle it in an event driven manner, responding to Input events inside your game loop.  You can also poll the device directly to see what it’s status is.  Both are comparable ways to work, simply pick the one that fits your work style the best or mix and match as need.

 

This example also shows how Transformable’s can be positioned in multiple ways.  In response to the arrow keys, we move our sprite relative to it’s previous position using the move() method.  Later we set the position directly using the setPosition() method.  There are several other options available including matrix transforms.

 

Our final example is going to show how to use a GLSL vertex and fragment shader with SFML.

 

Here are the shaders:

shader.frag

uniform sampler2D texture;
uniform float opacity;

void main()
{
    vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);

    gl_FragColor = pixel * vec4(1.0,1.0,1.0,opacity); 
}

shader.vert

void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

    gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;

    gl_FrontColor = gl_Color;
}

And finally our C++ code:

#include <SFML/Graphics.hpp>

int main(int argc, char** argv){

  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Hello Cruel World");
  
  sf::Texture texture;
  if (!texture.loadFromFile("GFSLogo.png"))
    return 42;

  sf::Sprite sprite(texture);
  sprite.setPosition(0, 0);

  sf::Shader shader;
  if (!shader.loadFromFile("shader.vert", "shader.frag"))
    return 42;
  
  float opacity = 1.0f;

  shader.setParameter("texture", sf::Shader::CurrentTexture);
  shader.setParameter("opacity", opacity);

  sf::Event event;

  sf::Clock clock;

  while (renderWindow.isOpen()){
    while (renderWindow.pollEvent(event)){
      if (event.type == sf::Event::EventType::Closed)
        renderWindow.close();

      if (event.type == sf::Event::EventType::KeyPressed){
        if (event.key.code == sf::Keyboard::Left)
          sprite.move(-1, 0);
        if (event.key.code == sf::Keyboard::Right)
          sprite.move(1, 0);
      }
    }

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)){
      sprite.setPosition(static_cast<sf::Vector2f>(sf::Mouse::getPosition(
                         renderWindow)));
    }

    if (clock.getElapsedTime().asSeconds() > 0.1){
      opacity -= 0.05;
      if (opacity < 0.0)
        opacity = 1.0;

      clock.restart();
      shader.setParameter("opacity", opacity);
    }

    renderWindow.clear(sf::Color::White);
    renderWindow.draw(sprite, &shader);
    renderWindow.display();
  }
}

 

When run:

sfml

 

Shaders are actually beyond the scope of this document, this does however illustrates it's fairly simple to load, pass parameters too and apply a shader in SFML.  There is slightly more details in the video version if you are interested.  Also for more information on GLSL check here.  One thing to be aware of however, shader support on iOS and Android is currently confined to OpenGL ES, which uses the fixed function pipeline, meaning no shader support.  I believe this is being addressed in future versions.

 

Functionality and 3rd Party Libraries

 

These are relatively minor examples, but they all give you a pretty good idea of what the coding experience is like and the consistency you should expect.  For the most part, SFML is a straight forward library that becomes intuitive very quickly.  In addition to what we have covered here, SFML also provides support for:

  • Sprite/Sprite Sheets
  • 2D Geometrics such as Circles and Rectangles
  • Render to texture
  • Vertex and Pixel Shaders
  • Joystick, Keyboard, Mouse, Touch and Sensor Events
  • UDP/TCP Networking
  • HTTP and FTP implementations
  • Audio Playback and Recording
  • Spatial Audio
  • Music Streaming
  • Threading and Mutex support in cross platform manner
  • Window creation and handling
  • Cross platform string with Unicode support
  • Math functionality including Matrix support
  • And More

 

SFML is focused on providing the underpinnings of a 2D game in a cross platform manner.  It however is not a full game engine, although there exist several community libraries build over top of SFML to provide game engine like functionality. 

Some of these third party libraries include (but are by no means limited to):

 

Thor 

Extends SFML adding animation, advanced math, more complex shapes, particle systems, timers and more.

 

sfeMovie

Built over FFMPeg, it adds the ability to play movies.

 

tmxLoader

A tmx (tiled) loader.  Other tilemap libraries exist.

 

Let There Be Light

Dynamic lighting library.

 

Documentation and Community

 

One very strong area for SFML is the documentation.  The reference materials are exceptional, and for many developers are all you will need 95% of the time.  Rarely is detail glossed over and often there are good examples illustrating the usage.  Additionally there are clickable inheritance diagrams making navigating familial hierarchies a breeze.

There are also a comprehensive set of tutorials that are kept current with each new release.  Quality is a bit more variable than the reference material, but for the most part the materials are quite good.  For a beginner starting out they will find the occasion hole to fall in.

The community is active on both the English and French forums.  The active community is somewhat small, and can be a bit… harsh in their response to repetitive posts, but for the most part questions go answered fairly quickly.  SFML is popular among the indie and amateur communities, so finding support in other forums such as gamedev.net, reddit or stackoverflow is also an option.

 

Books

 

SFML has been around for a number of years and as a result a couple of books on the subject are available:

sfmlblueprintbooksfmlessentialsbookssfmlgamedevbook

 

There is another title, SFML Game Development by Example coming in November.  SFML Game Development is the only title I have read and it is a very good book.

 

Conclusion

 

If you are looking for a lower level 2D multimedia library, especially if you want to work with C++, SFML is a great choice.  It is very similar to SDL in what it provides, although I personally find the SFML API to be much more to my taste.  The code is very clean, consistent and well documented.  It was however refactored for SFML 2.0, breaking backward compatibility with many older examples and tutorial series. 

 

Android and iOS support are finally available but are in the early stages so may not be quite as solid or stable as desktop platforms.  New releases used to come at a snails pace, so if you aren’t comfortable building from source and depend on critical bug fixes, this can certainly be an issue.  Recently however there have been great improvements in this regard and a nightly build option is now available.

 

Just be realistic in what you expect from SFML.  It is not a turn key game engine, nor is it a 3D (or 2.5D)  library.  If you are looking for either thing, look elsewhere.  It is however a very solid, well documented and well supported cross platform media layer for building a 2D game or game engine on top of. 

 

The Video

Programming


GFS On YouTube

See More Tutorials on DevGa.me!

Month List