Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
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


4. September 2015

 

While on vacation I have been looking at the process of extending the Godot Game engine using C++.  Due to the vacation, this isn’t a proper tutorial, I may do one later on when I have access to video, etc…  There is pretty solid documentation of the process in this post on the Godot wiki beyond that however there is a huge lack of information.  So the following is mostly trial and error.

 

I worked entirely in Visual Studio for this example and am working from the most recent source from Github.  If you have trouble working in Visual Studio with Godot, be sure to check out this post.

 

We are going to have to create several files in the modules folder, but don’t worry many can be copy/pasted from an existing module.  I created a new module called modTest inside the modules folder, and the contents end up looking like:

 

image

 

Many I coped directly from gridmap, but I will show the entire contents below.

 

config.py

def can_build(platform):
  return True
  
  
def configure(env):
  pass
  

 

SCSub

Import('env')

env.add_source_files(env.modules_sources,"*.cpp")


 

register_types.h

void register_modtest_types();
void unregister_modtest_types();

 

register_types.cpp

#include "register_types.h"
#include "object_type_db.h"
#include "modtest.h"
#include "modtest_editor.h"

#define TOOLS_ENABLED 1

void register_modtest_types() {
  ObjectTypeDB::register_type<ModTest>();

#ifdef TOOLS_ENABLED
  EditorPlugins::add_by_type<modtest_editor_plugin>();
#endif
}



void unregister_modtest_types() {


}

 

modtest.h

#ifndef MODTEST_H
#define MODTEST_H

#include "scene/2d/node_2d.h"

class ModTest : public Node2D {
  OBJ_TYPE(ModTest, Node2D);
};

#endif

 

modtest.cpp

#include "modtest.h"

 

modtest_editor.h

#pragma once

#include "tools/editor/editor_plugin.h"
#include "tools/editor/editor_node.h"
#include "tools/editor/pane_drag.h"


class ModtestEditor : public VBoxContainer {
  OBJ_TYPE(ModtestEditor, VBoxContainer);

public:
  ModtestEditor(){}
  ModtestEditor(EditorNode * p_editor);


private:
  VBoxContainer * container;
  Label* label;
  EditorNode* _editor;
};




class modtest_editor_plugin : public EditorPlugin
{
  OBJ_TYPE(modtest_editor_plugin, EditorPlugin);

public:
  modtest_editor_plugin(EditorNode *p_editor);
  ~modtest_editor_plugin();

  virtual void make_visible(bool isVisible);
  virtual void edit(Object *p_node);
  virtual bool handles(Object *p_node) const;

private:
  EditorNode * _editor;
  ModtestEditor* modtestEditor;
};

 

modtest_editor.cpp

#include "modtest_editor.h"
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
#include "tools/editor/editor_settings.h"

#include "scene/main/viewport.h"

#include <iostream>


ModtestEditor::ModtestEditor(EditorNode* p_editor){
  std::cout << "New Modtest Editor" << std::endl;

  this->set_size(Size2(600, 600));
  label = new Label();
  label->set_text("Hello World");
  this->add_child(label);

  //p_editor->add_child(this);
  p_editor->get_scene_root()->add_child(this);
  _editor = p_editor;
  
  this->hide();
}


// **************************** PLUGIN BEGIN ********************************************

modtest_editor_plugin::modtest_editor_plugin(EditorNode * p_editor)
{
  _editor = p_editor;
  modtestEditor = memnew(ModtestEditor(_editor));
  
  std::cout << "Editor" << std::endl;
  
}


modtest_editor_plugin::~modtest_editor_plugin()
{
}


void modtest_editor_plugin::make_visible(bool isVisible){
  std::cout << "Make visible" << std::endl;
  if (isVisible){
    std::cout << "Showing" << std::endl;
    modtestEditor->show();
  }
  else{
    std::cout << "Hiding" << std::endl;
    modtestEditor->hide();
  }
}

void modtest_editor_plugin::edit(Object *p_object) {
  std::cout << "Edit" << std::endl;
}

bool modtest_editor_plugin::handles(Object *p_object) const {

  return p_object->is_type("ModTest");
}


So that was a mountain of examples, but nothing particularly complicated.

 

The SCSub and config.py files simply tell the Scons build system how to build your module, both of them can be copied in unchanged from the gridmap module.  It’s only if your module doesn’t build for every platform or you need to do something other than compile all the included cpp files that you need to alter either of these files.

 

Next up are the register_types cpp and h files, which registers your type with Godot.  ModTest is a simple Node2D extension type, it can be registered using ObjectTypeDB::register_type().  Additionally we have an editor we want to show when editing our new type, that is registered using EditorPlugins::add_by_type() .  The TOOLS_ENABLED means that you are building Godot with full tooling support, as opposed to building just a game (without the editor in the generated binary).

 

Our extension is completely pointless.  It’s inherited from Node2D and well, that’s about it.  Obviously you would add functionality as you go.  The simple fact it inherits from Node2D makes it available in Godot as a Node:

image

 

Next we register an editor and a plugin for our ModTest type.  The ModtestEditor class is going to be the editor displayed within Godot.  It’s a simple VBoxContainer.  In this case all we do is add a label with the text Hello World then add it to the editor using the passed in pointer to the EditorNode.  This is generally where the majority of logic will go.

 

Next up is the modtest_editor_plugin which inherits EditorPlugin.  This class is loaded with Godot by the call EditorPlugins::add_by_type<modtest_editor_plugin>().  The important call is modtest_editor_plugin::handles(), which attaches the editor to the type it edits.  In the constructor, we create an instance of our editor.  The make_visible() method is called each time the editor is needed, or no longer needed and toggles the visibility of our editor.

 

As you add or select a node of ModTest type, the editor will automatically be shown:

image

 

Obviously this is a barebones example.  As I implement a more detailed example I will share the results.

Programming


GFS On YouTube

See More Tutorials on DevGa.me!

Month List