Please share...

First of all SFML is great and this is not a review about whether or not SFML is extremely cool or not. Trust me, it is extremely cool. This article will just explore what it can do, when it is best used and by whom. Also we will see who it is not for and what it should not be used for.

What SFML isn’t

Let’s quickly state was SFML is not. It is not an all-in-one solution for all your game development needs like Unreal Engine, CryEngine or Unity. It will not let you design huge realistic 3d worlds, build 3d models or create movie-like cut-scenes. Although if you are quite expert you can make 3d games with it, that is not it’s strength. It does not offer point and click tools for even 2d games like Game Maker Studio although you can build amazing 2d games far better than anything that can be done in GameMaker Studio*.

What it is

SFML is perfect for writing 2d games of any size or complexity at all. If you want to learn game coding and your favourite device is your PC, Mac or Linux; SFML is the best choice providing the above limitations are not an issue for you. If you dream of publishing 2d games for any of the desktop platforms, perhaps you want to get your cool idea onto Steam? If this describes you then SFML is for you.

SFML stands for simple fast media library and for once the acronym is entirely accurate. Let’s deal with the simple bit first.

Simple

Take a look at this next code sample. Don’t try and understand it just scan your eyes over it and then continue with the article.

// Win32Project4.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "Win32Project4.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WIN32PROJECT4, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT4));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT4));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WIN32PROJECT4);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

That was pretty scary!

The previous code is what you need to do in Windows to get a completely empty window- that does absolutely nothing!

If you have read any game development tutorials in the past you will know that there are components that all games need. A place/interface to draw your graphics, like-wise to control the logic of the game and handle input from the player. Furthermore the above code does not include a controlled loop known as the game loop to repeatedly process and draw all the frames of the game. Add all that into the code above and you will at least quadruple the code and it will be spread over multiple complex files.

Now consider if you want your game to run on Mac, PC and Windows then all of this code will be different for each of the desktop operating systems.

In the next code sample all the lines of code that start with // are comments to explain what is happening. Now look at this SFML code:

// Include some code from the SFML library
#include <SFML/Graphics.hpp>

// This is where our game starts
int main()
{
	// Make a window that is 1920 by 1080 pixels in size
    sf::RenderWindow window(sf::VideoMode(1920, 1080), "My Cool Game");

    while (window.isOpen())
    {// Game loop starts here

        //Handle input from the keyboard, mouse and controller

		// Process movement, AI and other logic here

		// Rub out the last frame
        window.clear();

		// Draw the current scene here

		// Show the current scene
        window.display();

    }// Do all of the above over and over again

// User has quit- go back to the operating system
    return 0;
}

The previous code not only does everything that the rather frightening Windows code did but it also provides a place to draw, process logic and handle player input. Oh yes, and the curly brace { next to the // Game loop starts here comment, down to the closing curly brace } by the comment that says // Do all of the above over and over again is the game loop. The same code can also be made(compiled) to run on all three of the major desktop operating systems.

We can then draw things to the screen with simple code like this.

// Draw a previously defined shape in the main game loop
window.draw(shape);

We can play soundFX with code like this:

// Play a previously prepared sound
sound.play();

We could even send packets of data over the Internet to build multi-player games with code as simple as this:

// Send a previously prepared message across the Internet to another computer
tcpSocket.send(message, msgSize);

It is true that as our projects grow into complete games they will become complex eventually but the point is that SFML is perfect, through it’s simplicity, for a beginner and yet because of it’s depth and speed is something we won’t grow out of if we have the dedication to become a professional. And we can steadily build up the complexity so it doesn’t overwhelm us.

What about the F for fast then?

Fast

C++ is a language which is turned (compiled) into native executable programs by the software (compiler) that we use to write our code. This means that it is super-fast because it works directly with the software subsystems of our computer without any layers to slow it down. I mentioned in the previous section that the simple SFML code we looked at previously included the game loop. On my ageing laptop that game loop runs at around 2000 frames per second. Of course as we add more logic and drawing into our games this will reduce but the point is SFML makes it simple to write very fast code.

Media Library

SFML is a library, a library of C++ code organized into 5 modules that handle all the fundamentals of game programming. We use the library by writing our own C++ code (like in the previous examples) to call the code from the SFML library. We don’t need to see this SFML library code, we don’t even really need to know how it works internally.

SFML conclusion

SFML IS NOT for you if:

  • You want to build amazing 3d worlds or characters especially if you want user friendly GUI tools
  • You want to build any type of game by pointing, clicking, dragging and dropping
  • You want your game done by tea time
  • You want to avoid learning and writing real code

SFML IS for you if :

  • You want the fastest possible language and library
  • You want to learn to actually code games from scratch
  • You are looking for a fun way to learn C++
  • You want to make 2d games for desktop (Mac, Windows, Linux) that can go way beyond more friendly environments like GameMaker Studio
  • You aspire to be a professional/indie developer who has a career making 2d games for desktop**

If you want to begin to learn C++ then take a look at the growing range of c++ game coding beginner tutorials and if you want to dive in to SFML straight away here is my click by click guide to getting started with SFML and Microsoft Visual Studio.

*I am not knocking GameMaker Studio it is a great tool but there are differences. It is true that you could have a simple working game in GameMaker Studio much faster than with SFML and if that is your goal then I highly recommend it.

**SFML can actually make games for Android and iOS. At the time of writing I am not considering any tutorials because it is complex, relatively untested and there are arguably better and simpler ways to make cross platform games between mobile and desktop. This could change of course and if it does, by learning SFML now you will be well placed to learn the extra steps to make games for mobile devices.