French Chinese (Simplified) Dutch English German Greek Italian Japanese Korean Spanish

     

 



 

 

Big Tuto SFML 2 : Rabidja v. 3.0

Chapitre 3 : Ouvrons notre première fenêtre sur le monde !

 

Tutoriel présenté par : Jérémie F. Bellanger (Jay81)
Date d'écriture : 12 février 2015
Date de révision : 19 mars 2016

      Prologue

     On va enfin rentrer dans le vif du sujet : le code source. Notre but est ici d'ouvrir une fenêtre. Or on peut ouvrir une fenêtre avec un simple main() comprenant tout le code (comme on vient de le faire pour tester la bonne configuration de la SFML wink), mais comme notre but, à terme, n'est pas simplement de s'amuser à ouvrir des fenêtres (Ah bon ?! ), nous allons déjà mettre en forme l'architecture de notre programme pour qu'il soit plus clair et donc plus facilement modifiable après !


    On va donc y aller progressivement ensemble. Pour chaque partie du code, je vais vous donner le nom de la page à créer ou à modifier (en haut en gras). Ensuite je vous donnerai le code commenté, puis une explication, plus ou moins longue selon le besoin.

   Comme, vous allez le voir, notre architecture va être bien plus minimaliste en SFML 2 qu'en SDL 2, puisque la lib va faire le plus gros du boulot pour nous. wink

   Reprenons donc d'abord notre fichier main.cpp et copions-y le code suivant (sans oublier de supprimer le code de démo précédent, si ce n'est pas déjà fait cheeky !) :

 

Nom du fichier : main.cpp

//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
//Big Tuto C++/SFML 2.2 - Février 2015 - Mise à jour 1.2
 
#include "main.h"
 
 
int main(int argc, char *argv[])
{
// Création d'une fenêtre en SFML
RenderWindow window(VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32),
"Rabidja 3.0 - Chapitre 3 - Big Tuto SFML2 - www.meruvia.fr");
 
//Limite les fps à 60 images / seconde
window.setFramerateLimit(60);
 
//On active la synchro verticale
window.setVerticalSyncEnabled(true);
 
//Instanciation des classes
Input input;
 
// Boucle infinie, principale, du jeu
while (window.isOpen())
{
/** GESTION DES INPUTS (CLAVIER, JOYSTICK) **/
input.gestionInputs(window);
 
/** DESSIN - DRAW **/
//On efface l'écran et on l'affiche
window.clear();
window.display();
}
 
// On quitte
return 0;
 
}

 

    Comme vous pouvez le voir, pour l'instant, notre main() est très minimaliste , mais c'est normal, puisqu'on veut simplement ouvrir une fenêtre !

    Cependant, il contient déjà l'architecture de base de notre jeu. En effet, d'abord on appelle la SFML 2 pour créer notre fenêtre et lui donner un titre, ensuite, on limite le framerate à 60 images/seconde (la SFML le fait toute seule, contrairement à la SDL wink) et on active la synchro verticale, pour éviter des saccades de l'écran, quand on fera défiler nos niveaux à fond la caisse ! laugh

    Ensuite, on instancie notre classe Input, que nous allons définir juste après, et qui servira à gérer les inputs (= entrée) du clavier, et plus tard du joystick.

    Après cette courte phase d'initialisation, on passe alors dans la boucle principale du jeu (while). Pour l'instant, on n'y fait pas grand chose. On teste l'état des inputs (donc du clavier) pour pouvoir quitter le programme, le cas échéant, puis on efface l'écran et on affiche notre écran noir. cheeky

    Voilà, il n'y a pas grand chose à dire de plus, c'est vraiment très basique, et ça ne devrait pas vous poser trop de problème normalement .

    Passons maintenant au fichier d'en-tête (header) de notre fonction main().

 
Nom du fichier : main.h
 
//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
 
#include <cstdlib>
#include <iostream>
#include <SFML/Graphics.hpp>
 
#include "input.h"
 
using namespace std;
using namespace sf;
 
// Taille de la fenêtre : 800x480 pixels
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480; 
 

    Rien que du très classique ici : on inclue d'abord les libs dont on va avoir besoin par la suite (sans oublier la SFML, of course ! laugh).

    Puis, on indique les namespaces que l'on va utiliser pour éviter de rajouter std:: et sf:: partout (même si ça peut faire jolie ! indecision).

    Et enfin, on définit la taille de notre fenêtre à l'aide de 2 constantes pour la largeur (width) et la hauteur (height). Vous aurez d'ailleurs remarqué qu'on s'est déjà servi de ces deux constantes dans la fonction d'ouverture de notre fenêtre. wink

   Passons maintenant au fichier input.cpp, qui contiendra notre nouvelle classe Input dont le but sera de détecter les entrées du clavier (puis plus tard du joystick wink).

 
Nom du fichier : input.cpp
 
//Rabidja 3 - nouvelle version intégralement en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
 
#include "input.h"
 
using namespace std;
using namespace sf;
 
//Constructeur
Input::Input()
{
button.left = button.right = button.up = button.down = button.jump =
button.attack = button.enter = false;
}
 
 
//Accesseur
Input::Button Input::getButton(void) const { return button; }
 
 
//Mutateur
void Input::setButton(int bouton, bool etat)
{
switch (bouton)
{
case up:
button.up = etat;
break;
 
case down:
button.down = etat;
break;
 
case right:
button.right = etat;
break;
 
case left:
button.left = etat;
break;
 
case attack:
button.attack = etat;
break;
 
case jump:
button.jump = etat;
break;
 
case enter:
button.enter = etat;
break;
}
}
 
 
//Fonctions
void Input::gestionInputs(RenderWindow &window)
{
//Pour l'instant, on ne gère que le clavier.
//On gèrera les joysticks plus tard, s'il y en a
//un de branché.
//Pour l'instant, cette fonction n'est donc pas indispensable.
getInput(window);
}
 
 
void Input::getInput(RenderWindow &window)
{
 
// Tant qu'il y a des évènements à traiter...
while (window.pollEvent(event))
{
// on regarde le type de l'évènement...
switch (event.type)
{
// On ferme la fenêtre
case Event::Closed:
window.close();
break;
 
// Touche pressée
case Event::KeyPressed:
switch (event.key.code) // La touche qui a été pressée
{
case Keyboard::Escape: // Echap
window.close();
break;
 
case Keyboard::C:
button.jump = true;
break;
 
case Keyboard::V:
button.attack = true;
break;
 
case Keyboard::Left:
button.left = true;
break;
 
case Keyboard::Right:
button.right = true;
break;
 
case Keyboard::Down:
button.down = true;
break;
 
case Keyboard::Up:
button.up = true;
break;
 
 
case Keyboard::Return:
button.enter = true;
break;
 
default:
break;
}
break;
 
// Touche relâchée
case Event::KeyReleased:
switch (event.key.code)
{
case Keyboard::C:
button.jump = false;
break;
 
case Keyboard::Left:
button.left = false;
break;
 
case Keyboard::Right:
button.right = false;
break;
 
case Keyboard::Down:
button.down = false;
break;
 
case Keyboard::Up:
button.up = false;
break;
 
 
case Keyboard::Return:
button.enter = false;
break;
 
default:
break;
}
break;
 
// on ne traite pas les autres types d'évènements
default:
break;
}
}
}

    Commençons par le constructeur de la classe, qui se contente d'initialiser notre structure Button, qui contiendra simplement un booléen pour chaque type d'entrée valide (right, left, enter, attack, jump, etc.) et qui nous dira donc si le bouton correspondant a été pressé ou non. Nous déclarerons cette structure et la variable correspondante dans notre header ci-dessous.

    Vient ensuite un bête accesseur, qui renvoie la struct button puis un mutateur qui nous permettra de changer la valeur (true ou false) de chaque entrée de notre structure, en-dehors de la classe Input. wink

    Vous remarquerez ensuite 2 fonctions : la première - gestionInputs() - renvoie pour l'instant simplement à la deuxième, mais elle va se complexifier plus tard, quand nous rajouterons les joysticks (sinon, elle serait inutile ! cheeky).

 

   La seconde - getInput() - est assez longue mais néanmoins très simple : elle enregistre tous les events/événements, c'est-à-dire ici les entrées clavier (on verra plus tard comment rajouter d'autres events pour le joystick). Ensuite, elle traite ces événements dans une boucle (while) jusqu'à ce qu'il n'y en ait plus. Là, il y a 3 grands cas traités dans un switch : ou on veut quitter en cliquant sur la croix, ou on appuie sur une touche, ou on la relâche. Si on appuie ou on relâche une touche, on met la valeur correspondante de notre structure bouton à 1 ou à 0, selon qu'elle est pressée ou pas.


    Ainsi, par exemple, tant que la touche C sera enfoncée, button.jump vaudra true et quand on la relâchera, elle vaudra false. L'utilisation qu'on en fera se trouvera plus tard dans la classe Player qui s'occupera de déplacer notre héros en fonction des touches du clavier. wink

   Passons maintenant au fichier d'en-tête input.h :


Nom du fichier : input.h
 
//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#ifndef INPUT_H
#define INPUT_H
 
#include <SFML/Graphics.hpp>
 
 
class Input
{
 
//Structures
struct Button { bool left, right, up, down, jump, attack, enter; };
 
public:
 
//Constructeur
Input();
 
//Accesseur
Button getButton(void) const;
 
//Mutateur
void setButton(int bouton, bool etat);
 
//Fonctions
void gestionInputs(sf::RenderWindow &window);
void getInput(sf::RenderWindow &window);
 
 
private:
 
//Variables de la classe en accès privé
sf::Event event;
Button button;
 
//Enum pour les boutons
const enum{ up, down, right, left, attack, jump, enter };
 
};
#endif 
   

    Et voilà, on déclare ici notre classe Input : on crée notre struct Button, puis on indique les prototypes de notre constructeur, de nos accesseurs / mutateurs et de nos deux fonctions.

    Ensuite, en privé (les variables ne seront donc accessibles que depuis l'intérieur de la classe, sauf en passant par un accesseur / mutateur), on initialise une variable SFML event pour stocker les inputs et une structure button.

    Enfin, pour pouvoir retrouver plus facilement nos boutons à l'aide de noms explicites (dans le switch), on crée une enumwink


    Et voilà, on a maintenant l'architecture de base de notre jeu !!! Il ne reste plus qu'à compiler, et Tadaaaaam ! On a notre magnifique fenêtre noire !!!

 


    Ouah ! Le magnifique monochrome noir ! J'ai bien fait de me mettre à la programmation, moi ! laugh 
Mais non, rassurez-vous, ça ne fait que commencer !!!  cheeky


 
 

Commentaires   

0 #11 jay81 28-01-2018 11:37
Bonjour et merci ;)

Pour la base de données, je ne vois pas bien de quoi tu parles ? :sad:

En revanche, le dossier Release est créé à la compilation, si tu compiles en mode Release, mais par défaut, VS doit être en mode Debug, le binaire (fichier .exe) doit donc être dans un dossier Debug.

La différence se situe dans le fait que le mode Debug permet de débuguer le programme tandis que Release est fait pour la version définitive (publiable) du programme. Mais cela ne devrait pas changer grand chose à ce niveau ;) .
0 #12 janpin 28-01-2018 12:09
Si tu ouvres le dossier RELEASE tu as le fichier Rabidja.pdb de type base de données donc ...?
Autre chose, chapitre 4, désolé je profite du présent commentaires .... le chargement dans le dossier graphics de background.pnb ne se fait pas, ne veut pas s'ouvrir en fait, et je suppose que c'est un pb d'adresse...Heu bon appétit tout de même :-* !
0 #13 jay81 28-01-2018 12:18
Ah d'accord, c'est un fichier système de VS pour gérer la compilation, tu n'en as pas besoin. ;)

Pour l'adresse du fichier, il faut la changer, si ce n'est pas la bonne sur ton disque. Le mieux, c'est une adresse relative par rapport au dossier Rabidja (le dossier du jeu). ;)

Bon appétit également. :P

Connectez-vous ou inscrivez-vous pour pouvoir poster.