Vous êtes sur la page 1sur 8

Les interfaces graphiques SFML 

Simple and Fast Multimedia Library 

Étape 1: Créer un nouveau projet

Créer un projet vide que vous nommez lostSFML et ajouter un fichier lostSFML.cpp et y
inclure ​<SFML/Graphics.hpp>​, ainsi que le main standard pour SFML. Doit être int avec
les paramètres suivants:
#include​ ​<​SFML/Graphics.hpp​>
int​ ​main()​ ​{
​return​ ​0​;
}

Étape 2: Installer la librairie SFML

Maintenant, nous devons télécharger la librairie et dire au compilateur où trouver les


en-têtes SFML (fichiers .hpp), et à l'éditeur de liens où trouver les bibliothèques SFML
(fichiers .lib).
1. Sur le site de téléchargement de SFML ​http://www.sfml-dev.org/​, vous téléchargez la
dernière versions soit la 2.5.1. ​Vous devez vous procurer la librairie qui est pour votre
version de ​Visual Studio​,​ soit 32 bits ou 64 bits​). Vous pouvez voir dans la barre d’outil
de votre Visual studio x86 ou x64 à côté de la liste déroulage où est écrit debug ou
release. X86 correspond au 32 bits et x64 au 64 bits. C’est très important de télécharger
la bonne version.

2. Extraire le contenu de l’archive à la racine du répertoire du projet lostSFML


L’archive contient plusieurs sous-dossiers. Ceux qui nous intéressent sont :
o bin​ : Contient les Dynamic Link Library ( ​.dll​ )
o include ​: contient les fichiers d’en-tête ( ​.hpp​ )
o lib ​: contient les generic data library ( ​.lib )

3. Pour installer SFML à votre projet, configurer Visual Studio en modifiant les
propriétés​ du projet

1. Dans “​Configuration Properties → C/C++ → General​”


Dans le champ “​Additional Include Directories​”, ajouter la ligne ci-dessous,
adaptée avec votre version de la librairie SFML:
$(SolutionDir)<Librairie SFML>\include

Exemple: ​$(SolutionDir)SFML-2.5.1\include

Attention au chemin absolu.​ $(SolutionDir) représente l’emplacement actuel,


mais il changera quand vous changerez le répertoire du projet de place,
comme quand je vais corriger chez moi plus tard. ​Vous ne devez donc pas
utiliser les chemins absolus.
2. Dans “​Configuration Properties → ​Linker​ → General​” cette fois, et inscrire
dans le champ “​Additional Library Directories​” la ligne suivante, encore une
fois, adaptée à votre version de SFML: ​$(SolutionDir)<Librairie SFML>\lib

Exemple: ​$(SolutionDir)SFML-2.5.1\lib

3. Dans “​Configuration Properties -> Linker -> Input​”, dans le champ


“​Additional Dependencies​”, vous allez ajouter les fichiers .lib que vous aurez
besoin.
- sfml-graphics-s-d.lib - freetype.lib
- sfml-window-s-d.lib - winmm.lib
- sfml-system-s-d.lib - gdi32.lib
- opengl32.lib

4. Dans “​Configuration Properties -> C/C++ -> Preprocessor​” et ajouter


“​SFML_STATIC​” au champ “​Preprocessor Definitions​”

5. Générer votre projet et si tout compile bien, vous êtes maintenant prêt à coder.

6. Coder le main suivant et assurez-vous de comprendre ce qu’il fait.


#include <SFML/Graphics.hpp>
using namespace ​sf​; //en mettant ce namespace, ça évite des sf::
int ​main() {
RenderWindow ​window(​VideoMode​(800, 600), ​"Lost"​);
Event​ event;
RectangleShape​ fondEcran;
fondEcran.setSize(​Vector2f​(100, 100));
fondEcran.setFillColor(​Color​::Green);

while​ (window.isOpen()){
while​ (window.pollEvent(event)){
if​ (event.type == ​Event​::Closed)
window.close();
}
window.clear();
window.draw(fondEcran);
window.display();
}
return​ 0;
}

Étape 3: Manipuler la fenêtre et event loop


Tout au long de ce laboratoire, plusieurs choses seront à lire ou à confirmer par des
lectures supplémentaires dans la documentation SFML qui est super bien conçue et très
claire : ​https://www.sfml-dev.org/documentation/2.5.1-fr/

De plus, vous trouverez un tutoriel séparé par section qui introduit les objets principaux à
l’aide d’exemples, ce qui rend l’apprentissage plus facile et graduel. Les étapes de ce
laboratoire sont sensiblement dans le même ordre que ce tutoriel.
https://www.sfml-dev.org/tutorials/2.5/index-fr.php
Le programme que nous voulons bâtir, est un petit bonhomme qui se promène dans la
fenêtre avec les directions, comme votre snake, mais qui bouge les jambes avec des
images qui se succèdent (sprite).

Pour créer une fenêtre, il faut créer un objet ​RenderWindow​. On peut la créer et modifier
ses paramètres comme le titre, la taille, si elle est resizable ou non, etc… Pour faire les 3
étapes suivantes, vous devez lire la documentation sur les fenêtres à l’adresse :
https://www.sfml-dev.org/tutorials/2.5/window-window-fr.php

1. Pour notre exemple, la fenêtre est en 800 x 600, non-redimensionnable.


Attention au mode plein écran et au mode sans bordure. Comme il n'y a pas de
barre de titre dans ces 2 modes, vous ne pourrez pas fermer le programme.
2. Spécifier la limite du framerate de la fenêtre à 60.
3. Modifier la taille du RectangleShape et sa couleur pour qu’il soit la même grandeur
que la fenêtre pour créer un fond blanc. C’est la façon de mettre une couleur de fond.
Un RectangleShape ressemble beaucoup à notre objet rectangle, il offre les mêmes
possibilités et plus encore :
https://www.sfml-dev.org/documentation/2.5.1-fr/classsf_1_1RectangleShape.php
rectangle.​setPosition​(10, 20); //défini sa position
​ ector2f​(100, 50));
rectangle.​setSize​(V //défini ses dimensions
rectangle.​setOutlineColor​(C ​ olor​::Red​); //défini la couleur et
rectangle.​setOutlineThickness​(5); //l’épaisseur de la bordure

Étape 4: Les événements


Comme dans le snake, le mastermind et le blockudoku, on a besoin d’une main loop qui
détermine jusqu’à quand le jeu continue. Ici, c’est la fermeture de la fenêtre qui arrête le
programme pour le moment. On ajoutera d’autres conditions selon le jeu plus tard.

Pour saisir les événements, on a besoin de l’objet Event et d’une méthode de la fenêtre
qui écoute ce qui se passe au niveau des périphériques et quand un événement est
détecté, il est affecté dans l’instance d’Event qui se nomme event. Par la suite, on peut
questionner event pour savoir ce qui s’est passé. D’où le
if(​event​.type == Event::Closed)
Les 2 méthodes qui écoutent les événements sont ​pollEvent ​et ​waitEvent. Leur
différence est que le waitEvent attend qu’un événement se produire et après il continue
d’exécuter son code. C’est pratique pour les jeux ou l’action est déterminée par
l’événement et entre temps, il ne se passe rien. Comme on veut créer un bonhomme qui
avance seul sans qu’aucune touche ne soit appuyée, on doit utiliser pollEvent.

1. Ajouter la condition qui ferme la fenêtre quand on appuie sur la touche ESC.
else if ​(event.type == ​Event​::KeyPressed) {
switch​ (event.key.code) {
case​ ​Keyboard​::Escape:
window.close();
break​;
}
}
2. Créer un autre RectangleShape position que vous positionnez au milieu de l’écran,
de dimensions 10x10 et de couleur bleue. Faîtes-le afficher.
3. Nous allons ajouter les conditions nécessaires pour que le carré bleu se déplace dans
l’écran selon les flèches appuyées.
else if ​(event.type == ​Event​::KeyPressed){
switch ​(event.key.code) {
case​ ​Keyboard​::Escape:
window.close();
break​;
case​ ​Keyboard​::Up:
//code pour déplacer le carré bleu vers le haut de 10 pixels
break​;
case​ ​Keyboard​::Right:
//code pour déplacer le carré bleu vers la droite de 10 pixels
break​;
case​ ​Keyboard​::Down:
//code pour déplacer le carré bleu vers le bas de 10 pixels
break​;
case​ ​Keyboard​::Left:
//code pour déplacer le carré vers la gauche de 10 pixels
break​;
}
}
4. Pour voir le rectangle ​bouger à l’écran​, on doit “rafraîchir” la fenêtre. À chaque
loop principale, après 1 événement, on veut effacer et réafficher la fenêtre. Ce cycle
clear/draw/display est la seule bonne manière de dessiner. N'essayez pas d'autres
stratégies, telles que garder certains pixels de la frame précédente, "effacer" des
pixels, ou bien encore dessiner une seule fois et appeler display plusieurs fois. Vous
obtiendrez des résultats bizarres à cause du double buffering.
Les puces et les APIs graphiques modernes sont vraiment faites pour des cycles
clear/draw/display répétés, où tout est complètement rafraîchi à chaque itération de
la boucle de dessin. Ne soyez pas effrayés de dessiner 1000 sprites 60 fois par
seconde, vous êtes bien loin des millions de triangles que votre machine peut gérer.
Étape 5: Afficher des formes avec texture dans la fenêtre
Dans cette section, vous apprendrez à utiliser les ​sf​::​Texture et les ​sf​::​Sprite pour être en
mesure de mettre des images dans vos formes ou de mettre plusieurs images pour une
forme et générer une animation.

1. Création et utilisation d’une texture pour votre rectangle​ : La classe ​sf​::​Texture


permet de ​charger une texture et de l'​appliquer à un drawable object (Shape,
Sprite, Text). Prenez le fichier charsets.bmp sur mon site et copiez-le dans le
répertoire du projet dans le répertoire où se trouvent les fichiers sources ou dans un
répertoire ressources créé à cet endroit (ceci est une excellente pratique lorsqu’on en
a plusieurs et c’est souvent le cas. Police, image, musique, etc.. ).
Charger la texture et appliquez-la à votre RectangleShape position.
Texture​ textutreBonhomme;
if​ (!textutreBonhomme.loadFromFile(​"ressources/charsets.bmp"​))
return​ 1; //si incapable de loader, sort du main

position.setTexture(&textutreBonhomme);//Applique la texture à position


window.draw(posBonhomme);

2. Vous voyez toutes les images du bonhomme, ce n’est pas tout à fait ça
qu’on veut, on veut en voir qu’une et la changer selon les événements.
La méthode setTextureRect est une méthode faite pour ça, elle va créer
un rectangle dans l’image comme si elle découpait le rectangle dont
vous avez besoin dans l’image. Comme chaque bonhomme est 32x32,
on pourrait le faire commencer par le premier.
IntRect​ rectImage(0, 0, 32, 32);
position.setTextureRect(rectImage);

Modifier la position de l’image, les 2 premiers paramètres pour prendre l’image du


bonhomme qui est de face les jambes égales. La 2e image de la 1ère ligne, on
change donc le x.

3. Modifier ​rectImage​, selon la direction et le déroulement avec ​setTextureRect en


écrivant le x et y où se trouve l’image à prendre. ​Intégrer à votre switch le code
nécessaire pour ​changer l’image selon la direction et pour que les jambes bougent à
chaque déplacement. Un intRect est une structure, alors on peut modifier ses parties
directement,
rectSprite.top = 32; //choisi la bonne ligne selon la direction
rectSprite.left += 32; //change l’image horizontalement
if​(rectSprite.left >= 96) //Après 3, on revient à la première à 0
rectSprite.left = 0;
Si vous voyez que vous prenez la bonne série d’images pour la direction choisie
mais que le comportement du bonhomme est étrange. Il n’avance pas régulièrement,
les jambes bougent mais pas toute seule sauf si on clique tout le temps sur les
directions. Vous êtes prêt à passer à l’étape suivante pour régler ce problème.

Étape 6: Ajouter le temps


SFML a une classe très simple pour mesurer le temps : ​sf::Clock​. Elle ne possède que
deux fonctions : ​getElapsedTime​, pour récupérer le temps écoulé depuis son démarrage,
et ​restart​, pour la redémarrer.
Clock​ clock; //Mettre avec les autres variables au début du main
Time​ time;
...
while ​(window.isOpen()){

while(window.pollEvent(event)){
... ​//Dans le switch des touches, on ne modifie que dir =
}

time = clock.getElapsedTime(); //Prends le temps de l’horloge


if​(time.asMilliseconds() >= 50.0f){ //à chaque ½ seconde
//copier les instructions qui modifient de la position
//du bonhomme selon la direction modifiée dans le switch du while
...
//copier les instructions qui modifient l’image choisie
...
window.clear();
window.draw(fondEcran);
window.draw(posBonhomme);
window.display();

time = clock.restart(); //remet l’horloge à 0


}
}

Étape 7: Les collisions

Ajouter les conditions nécessaires pour que le bonhomme ne dépasse pas les limites de
l’écran. Attention de ne pas faire ces conditions dans le switch et la répéter 4 fois, elle peut
être après et être juste une fois. Comme le sprite est de 32x32, on doit s’assurer que le x
n’est pas > 800-32 et s’il l’est, on le remet à 800-32, dernière position possible à droite, il
se cogne donc dans le mur et marche sur place tant qu’on ne change pas de direction.
Étape 9: Afficher du texte
On veut écrire au bonhomme qu’il doit tourner car il est en collision avec les murs et quand
une touche est appuyée, on efface le texte.

Avant de dessiner du texte, vous avez besoin d'une police de caractères et celle-ci
Font ​font;
if ​(!font.loadFromFile(​"ressources/arial.ttf"​))
return ​1;

Vous devez avoir le fichier arial.ttf avec les ressources de votre application, comme
n'importe quelle autre ressource (images, sons, ...).

Pour écrire, vous devez dessiner du texte avec l’objet Text comme suit:
Text​ text;
text.setFont(font); ​//Set la police à utiliser (elle doit avoir été loadée)
text.setString(​"Attention aux murs!"​); //Set le texte à afficher
text.setCharacterSize(24); //Set la taille (en pixels)
text.setFillColor(​Color​::Red); //Set la couleur du texte
text.setStyle(​Text​::Bold | ​Text​::Underlined); //Set le style du texte
...
// puis, dans la boucle de dessin, entre window.clear() et window.display()
window.draw(text);

1. Écrire ce message ​au milieu de l’écran en rouge et en gras quand votre bonhomme
fonce dans un mur et dès que vous changez de direction ou longer un mur, ça ne
l’écrit pas. Attention de ne pas faire du code plein de répétition. Vous pouvez
utiliser des flags bool collisionX et collisionY et quand un des 2 est à true, on draw.

Étape 10: Faire des fonctions et des objets


Bien sûr, nous ne perdrons pas nos bonnes habitudes, même dans nos projets avec de
nouvelles librairies, nous allons faire des fonctions, des objets, etc…

1. Faites une fonction qui se nommera ​setText ​qui s’occupera de tout faire
l’initialisation des éléments nécessaires pour afficher du texte.. Ce sera bien efficace
car nous allons en faire souvent.
​ Attention aux murs!"​, font, ​"ressources/arial.ttf"​,
setText(text, "
800 / 2 - 100, 600 / 2 - 24, 24, ​Color​::Red, ​Text​::Bold);

Voici le prototype de la fonction pour que vous voyiez les types de paramètres et les
types de passage en paramètre.

void ​setText(​Text​ &text, ​const​ ​char​* message, ​Font​& font, ​const​ ​char​* police,
int​ posX, ​int​ posY, ​int​ taille, ​const​ Color& color, i ​ nt​ ​style);

Text ​et ​Font ​sont les 2 objets SFML nécessaires pour créer le texte avec la font, alors les
2 sont passés par référence et seront modifiés dans la fonction, mais nécessaire au main
pour faire le draw au bon moment. D’où le ​passage en référence​ pour avoir accès à
l’instance du main à la modification.
Le message et le nom de la police sont passés dans un ​const char *​. Ce type est tout
désigné lorsqu’on veut permettre lors de l’appel un passage une chaîne de caractères entre
guillemets. On veut éviter la string pour ce genre de paramètre, car elle n’est pas primitive
et elle est donc plus lourde à utiliser pour un simple passage en paramètre. On évitera
aussi un tableau de char (char message[]), pour ne pas avoir de problème de dépassement
de mémoire.

Les autres paramètres sont des types primitifs qui seront juste utilisés dans la fonction
pour setter les paramètres du text et de la police, donc passage par valeur bien suffisant.
Et la couleur était un objet, que nous ne modifierons pas dans la fonction, est passée par
référence constante qui est le passage par valeur des objets pour éviter la copie inutile et
protéger celui-ci de la modification.

2. Faites une fonction qui se nommera ifCollision qui retournera true si le bonhomme
frappe un mur et false sinon.
bool​ ifCollision(bonhomme& bob);

3. Si on voulait faire un objet, il est évident que ce serait le bonhomme, un peu comme
dans le snake. Faîtes l’objet bonhomme comme ceci et modifier votre main pour
remplacer les éléments du bonhomme par les méthodes de la classe.
class ​bonhomme{
private​:
RectangleShape​ _posBonhomme;
Texture​ _textutreBonhomme;
IntRect​ _rectSprite;
public​:
void​ init(​int​ posX, ​int​ posY, ​int​ _w, i
​ nt​ _h,
IntRect​ rectSprinte, ​const​ c ​ har​* nomSprite);
RectangleShape​ getRectangleShape()​const​;
Vector2f​ getPosition()​const​;
IntRect​ getIntRect()​const​;
Texture​ getTexture()​const​;

void​ setRectangleShape(​int​ posX, ​int​ posY, ​int​ _w, ​int​ _h);


void​ setPosition(​int​ posX, ​int​ posY);
void​ setIntRect(​IntRect​ intRect);
void​ ​ har​* nomSprite);
setTexture(​const​ c

void​ move(​int​ dir);


void​ print(​RenderWindow​ &window)​const​;
};

Maintenant que vous avez compris les bases, vous devez pratiquer avant de vous
lancer dans votre projet final. Tentez de refaire votre snake en SFML ou même le
Blockudoku qui serait super intéressant, si vous voudriez faire un Tétris ensuite.

Bonne pratique.