Tutorial 01 – Introduction – Plus or Minus



SFML is a cross-platform API. It supports Windows, Linux and Mac. Its license makes it free even for commercial use. It was created by the french programmer Laurent Gomila in C++ and there are bindings for various languages. SFML 2 is available on www.sfml-dev.org.

In this tutorial we will learn its basics through simple examples. I will be developing on Windows using Visual C++ 10 but it should be applicable to other configurations.

SDML Overview:

SFML is made of 5 modules: Graphics, Audio, Network, Window and System.

Each module provides its own header, lib and dll which must respectively be included, linked and present in the path to be used.

In this tutorial, we will see how to display windows, render text, respond to events and make a simple game using SFML2.





So, how to display a basic window ?



First, we’ll create a window then we’ll display it, it’s as simple as it should be.

All SFML classes and structures are in the namespace sf. You can either use namespace sf or use the sf:: prefix to avoid namespace conflicts.

The Window class is obviously in the Window module. We’ll use it by including its header, SFML\Window.hpp, and linking its library, sfml-window.lib.

There are multiple ways to tell the compiler to link SFML libs. For instance with Visual C++ you can use the following code or edit the project settings.

#ifdef _MSC_VER # ifdef _WIN32 # ifndef _DEBUG # pragma comment( lib, "sfml-window.lib" ) # else # pragma comment( lib, "sfml-window-d.lib" ) # endif # endif #endif

The default Window constructor doesn’t actually create the window, so we’ll use:

Window (VideoMode mode, const std::string & title)

We need to create a VideoMode that will set the resolution of our window. The default VideoMode constructor sets the resolution to 0x0, so we’ll use:

VideoMode (unsigned int modeWidth, unsigned int modeHeight)

Then we can display the window with its display() function. Please note that the constructor we used

will already call a display of the window frame. The display function draws the inside. Afterwards we close it with close(). In order to actually see it we’ll call a system(“PAUSE”) before closing it.

#include <SFML/Window.hpp> using namespace sf; int main() { VideoMode videoMode(320,240); Window window(videoMode,"Basic Display Window"); window.display(); system("PAUSE"); window.close(); return EXIT_SUCCESS; }

Result:

A black empty window is displayed on the screen in addition to the console, it doesn’t respond to any events so there is no way to give it focus.

We can minimize all windows that are in front to see it better but that leaves an image on our window cause it doesn’t even refresh the display.





How to refresh the display ?



We’ll just call it again and again in an infinite loop.

#include <SFML\Window.hpp> using namespace sf; int main() { VideoMode videoMode(320,240); Window window(videoMode,"Basic Infinite Loop Display"); while (true) { window.display(); } return EXIT_SUCCESS; }

Result:

It refreshes the display correctly, after a another window passes in front of this window, it goes back to black.

It still doesn’t respond to events and it never returns so it must be killed after execution.





How to make the window respond to event ?



First we declare an Event called event. The window.pollEvent(event) function sets event to the first event on top of the event stack, removes it from the stack and returns true. If the event stack is empty it returns false.

We will process all events of the stack using:

while (window.pollEvent(event))

We can then perform any action required according to the data contained in event. For instance, if event.type is of value Event::Closed, it means that the window has received a close request. We’ll also get rid of that horrible infinite loop by looping only if the window is open.

#include <SFML\Window.hpp> using namespace sf; int main() { VideoMode videoMode(320,240); Window window(videoMode,"Responsive Window"); while (window.isOpen()) { window.display(); Event event; while (window.pollEvent(event)) { if (event.type == Event::Closed) window.close(); } } return EXIT_SUCCESS; }

Result:

The window can be closed using the close button on the title bar of the window. It can also be minimized, maximized or resized without additional code.





How to also use the key esc to quit ?



In the same way that event.type can equal Event::Closed it can also be

Event::KeyPressed.

In that case event is of type KeyEvent and event.key.code has a different value

for each key. If it is equal to Keyboard::Escape then we’ll close the window.

#include <SFML\Window.hpp> using namespace sf; int main() { VideoMode videoMode(320,240); Window window(videoMode,"KeyEvent Window"); while (window.isOpen()) { window.display(); Event event; while (window.pollEvent(event)) { if (event.type == Event::Closed) window.close(); else if (event.type == Event::KeyPressed) { if (event.key.code==Keyboard::Escape) window.close(); } } } return EXIT_SUCCESS; }

Result:

As expected, the escape key closes the window.

Note that the condition to close the window can be united in only one if as the expression:

if ( (event.type == Event::Closed) ||

((event.type == Event::KeyPressed) && (event.key.code==Keyboard::Escape)) )

How to draw a rectangle ?



There are 3 classes of Shape that are drawable in SFML: RectangleShape, CircleShape and ConvexShape.

They are in the Graphics module and they require the use of a RenderWindow. This class inherits

from Window and also from RenderTarget which provides it with a clear function to quickly erase the screen.

We”ll create a RectangleShape, the default constructor sets its size to 0 x 0. So we’ll use setSize to configure its size, setPosition for its position, setFillColor and setOutlineColor to set its colors. We’ll use setOutlineThickness to adjust the border width. And we’ll update its position with arrow keys using the move function which calls setPosition itself. Of course, we need to call window.draw(rectangle) and clear the screen between two display calls.

#include <SFML\Graphics.hpp> using namespace sf; int main() { VideoMode videoMode(320,240); RenderWindow window(videoMode,"KeyEvent Window"); RectangleShape rectangle; rectangle.setPosition(30, 30); rectangle.setSize(Vector2f(50, 30)); rectangle.setFillColor(Color::Yellow); rectangle.setOutlineColor(Color::Blue); rectangle.setOutlineThickness(3); while (window.isOpen()) { window.clear(); window.draw(rectangle); window.display(); Event event; while (window.pollEvent(event)) { if ( (event.type == Event::Closed) || ((event.type == Event::KeyPressed) && (event.key.code==Keyboard::Escape)) ) window.close(); else { if (event.type == Event::KeyPressed) { switch(event.key.code) { case Keyboard::Up: rectangle.move(0,-10); break; case Keyboard::Down: rectangle.move(0,10); break; case Keyboard::Left: rectangle.move(-10,0); break; case Keyboard::Right: rectangle.move(10,0); break; } } } } } return EXIT_SUCCESS; }

Result:







How to display text ?



Text is a class of the Graphics module. It contains a String (from the System module), a Color, a Font and a bounding rectangle. So we’ll also use the System module.

Text text(“Hello”) creates the object and window.draw(text) displays it.

#include <SFML\System.hpp> #include <SFML\Graphics.hpp> using namespace sf; int main() { VideoMode videoMode(320,240); RenderWindow window(videoMode,"Hello Text"); Text text("Hello

SFML 2

World!"); text.setPosition(20,10); //text.setColor(Color::Red); while (window.isOpen()) { window.clear(); window.draw(text); window.display(); Event event; while (window.pollEvent(event)) { if ( (event.type == Event::Closed) || ((event.type == Event::KeyPressed) && (event.key.code==Keyboard::Escape)) ) window.close(); } } return EXIT_SUCCESS; }

Result:



How to use fonts ?



Open a font file:

Font::loadFromFile (const std::string & filename)

There are about 10 supported font file formats (notably ttf and fnt).

Create the text using the font with a pointSize of 20.

Text text(“Hello

SFML 2

World!”,font,20)

You’ll need to have the font file on your disk at run time, here “tomb.ttf”.

#include <SFML\System.hpp> #include <SFML\Graphics.hpp> using namespace sf; int main() { VideoMode videoMode(320,240); RenderWindow window(videoMode,"Hello Text"); Font font; if (!font.loadFromFile("tomb.ttf")) return EXIT_FAILURE; Text text("Hello

SFML 2

World!",font,20); text.setPosition(20,10); text.setColor(Color::Red); while (window.isOpen()) { window.clear(); window.draw(text); window.display(); Event event; while (window.pollEvent(event)) { if ( (event.type == Event::Closed) || ((event.type == Event::KeyPressed) && (event.key.code==Keyboard::Escape)) ) window.close(); } } return EXIT_SUCCESS; }

Result:







How to make the game of plus or minus ?



This may be one of the simplest game ever.

Player 1 picks a number x between 0 and 100.

Player 2 tries to guess x by proposing a number y

Player 1 tells player 2 if y is inferior, equal or superior to x.

Player 2 wins if he guesses x correctly and loses if he needs more than 10 tries.

Here the computer will play player 1 and we will try out the role of player 2 while play testing this game.

We will use the rand function of stdlib. It must be initialised (seeded) with srand. The same seed will generate the same sequence of random numbers so we will use time(NULL) as seed.

srand(static_cast (time()));

We need to capture the text entered by the user with TextEvent. If its a number we append it to textEntered, if it’s return, we process it and we ignore other characters.

To process it, we convert textEntered to an int and we compare it with the secret number, then we set textEntered to an empty string, awaiting the next try.

#include <SFML/System.hpp> #include <SFML/Graphics.hpp> #include <ctime> #include <sstream> using namespace sf; using namespace std; int main() { VideoMode videoMode(320,240); RenderWindow window(videoMode,"Plus Or Minus"); Font font; if (!font.loadFromFile("tomb.ttf")) return EXIT_FAILURE; Text title("Plus Or Minus",font,20); title.setPosition(10,10); title.setColor(Color::Blue); Text question("What is your guess ?",font,20); question.setPosition(5,30); question.setColor(Color::White); Text enter("",font,20); enter.setPosition(5,50); enter.setColor(Color::Green); String textEntered; int numEntered=0; Text status("",font,16); status.setPosition(100,50); status.setColor(Color::Yellow); stringstream out(""); Text won("You have discovered

the secret number

in less than 10 tries,

well played !",font,20); won.setPosition(5,70); won.setColor(Color::Green); Text lost("You have failed to

discover the secret

number in less than

10 tries, better

luck next time!",font,20); lost.setPosition(5,70); lost.setColor(Color::Red); srand(static_cast<unsigned int> (time(NULL))); int secretNumber = rand() % 100; bool isGameOn=true; bool playerWon=false; int tryNumber=0; while (window.isOpen()) { window.clear(); window.draw(title); if (isGameOn) { window.draw(question); window.draw(enter); window.draw(status); } else { if (playerWon) window.draw(won); else window.draw(lost); } window.display(); Event event; while (window.pollEvent(event)) { if ( (event.type == Event::Closed) || ((event.type == Event::KeyPressed) && (event.key.code==Keyboard::Escape)) ) window.close(); if (event.type == Event::TextEntered) { char c=static_cast<char> (event.text.unicode); if (c >= '0' && c <= '9' ) { textEntered += event.text.unicode; enter.setString (textEntered); //update the enter Text } else if (c == '\r') //'\b' to handle backspace { tryNumber++; stringstream in(enter.getString()); in >> numEntered; //just get str as an int if (numEntered>secretNumber) { out << tryNumber; out << ". "; out << numEntered; out <<": Minus" << endl; status.setString(out.str()); } if (numEntered<secretNumber) { out << tryNumber; out << ". "; out << numEntered; out <<": Plus" << endl; status.setString(out.str()); } if (numEntered==secretNumber) { playerWon=true; status.setString(""); isGameOn=false; } if (tryNumber>10) { playerWon=false; status.setString(""); isGameOn=false; } textEntered =""; //reset textEntered } } } } return EXIT_SUCCESS; }

Result:

The next tutorial will cover animations, collisions and pong.