Big Tuto SFML 2 : Rabidja v. 3.0

Chapitre 13 : Affichons le HUD !

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

      Prologue

   Bon, c'est bien beau ces petites collisions avec les monstres, mais on ne sait même pas combien de coeurs à notre héros ! angry

   Oh, là, calmos amigos ! cheeky Ca vient ! wink On va s'occuper ici d'afficher le HUD.

   Mais c'est quoi c'te bête, le heude ? frown

   C'est de l'anglais, ça veut dire Head Up Display ou Affichage Tête Haute. wink C'est tout simplement l'affichage sur l'écran des informations importantes relatives au jeu. Et ici, on va en afficher 3 : le nombre de coeurs, évidemment, mais aussi le nombre de vies, et enfin le nombre d'étoiles ramassées (et devinez quoi !? Au bout de 100, on gagnera une vie cheeky). 

   Allez, on est parti !

 

      Nouveaux fichiers à ajouter au projet

   Avant de commencer, il va nous falloir ajouter 3 nouveaux fichiers à notre projet :

- un fichier font ou police de caractères, que je vous laisse télécharger avec l'archive ci-dessus. wink Copiez-la dans un nouveau répertoire font, dans votre projet. Pour la police, j'ai choisi Gentium car c'est une open font (vous pouvez l'utiliser gratuitement et la redistribuer avec votre jeu, ce qui n'est pas le cas de toutes les polices (attention notamment aux polices Windows qui ne sont pas libres wink).

- 2 fichiers images qui nous serviront à afficher les vies (tête de Rabidja) et les étoiles ramassées. Ces images devront être copiées dans le répertoire graphics de votre projet. wink

              

            life.png          stars.png

      Le code

   On va commencer par retourner dans notre header map.h, pour y ajouter de nouvelles variables et les prototypes de nos 2 nouvelles fonctions : 

 

Fichier : map.h : Remplacer le code précédent par :

//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
 
#ifndef MAP_H
#define MAP_H
 
#include <SFML/Graphics.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
 
class Player;
class Monster;
 
class Map
{
public:
 
//Constructeur
Map();
 
//Accesseurs
int getBeginX(void) const;
int getBeginY(void) const;
int getStartX(void) const;
int getStartY(void) const;
int getMaxX(void) const;
int getMaxY(void) const;
int getTile(int y, int x) const;
int getLevel(void) const;
int getNombreMonstres(void) const;
 
//Mutateurs
void setLevel(int valeur);
void setStartX(int valeur);
void setStartY(int valeur);
void setTile(int y, int x, int valeur);
void setNombreMonstres(int valeur);
 
//Fonctions
void drawBackground(sf::RenderWindow &window);
void loadMap(std::string filename);
void draw(int layer, sf::RenderWindow &window, Monster monster[]);
void changeLevel(void);
void testDefilement(void);
void drawText(sf::RenderWindow &window, std::string message, int size, int x, int y, sf::Color color);
void drawHud(Player &player, sf::RenderWindow &window);
 
 
private:
//Variables de la classe en accès privé
 
//Numéro du tileset à utiliser
int tilesetAffiche;
 
/* Coordonnées de départ du héros, lorsqu'il commence le niveau */
int beginx, beginy;
 
/* Coordonnées de début, lorsqu'on doit dessiner la map */
int startX, startY;
 
/* Coordonnées max de fin de la map */
int maxX, maxY;
 
/* Tableau à double dimension représentant la map de tiles */
int tile[150][400];
 
//Deuxième couche de tiles
int tile2[150][400];
 
//Troisième couche de tiles
int tile3[150][400];
 
/* Timer et numéro du tileset à afficher pour animer la map */
int mapTimer, tileSetNumber;
 
//Numéro du niveau en cours
int level;
 
//Background
sf::Texture backgroundTexture;
sf::Sprite background;
 
//Tilesets
sf::Texture tileSet1Texture;
sf::Sprite tileSet1;
sf::Texture tileSet1BTexture;
sf::Sprite tileSet1B;
 
//Nombre max de monstres à l'écran
int nombreMonstres;
 
//Police de caractères
sf::Font font;
 
//HUD
sf::Texture HUDViesTexture;
sf::Sprite HUDVies;
sf::Texture HUDEtoilesTexture;
sf::Sprite HUDEtoiles;
 
 
/*******************/
/* Constantes */
/******************/
 
// Taille de la fenêtre : 800x480 pixels
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;
 
/* Taille maxi de la map : 400 x 150 tiles */
const int MAX_MAP_X = 400;
const int MAX_MAP_Y = 150;
 
/* Taille d'une tile (32 x 32 pixels) */
const int TILE_SIZE = 32;
 
/* Constante pour l'animation */
const int TIME_BETWEEN_2_FRAMES = 20;
 
//Nombre max de monstres gérés
const int MONSTRES_MAX = 50;
 
 
/*************************/
/* VALEURS DES TILES */
/************************/
 
// Constante définissant le seuil entre les tiles traversables
// (blank) et les tiles solides
const int BLANK_TILE = 99;
 
//Plateformes traversables
const int TILE_TRAVERSABLE = 80;
 
//Tiles Power-ups
const int TILE_POWER_UP_DEBUT = 77;
const int TILE_POWER_UP_FIN = 79;
const int TILE_POWER_UP_COEUR = 78;
 
//Autres Tiles spéciales
const int TILE_RESSORT = 125;
const int TILE_CHECKPOINT = 23;
const int TILE_MONSTRE = 136;
const int TILE_PIKES = 127;
 
//Tiles plateformes mobiles
const int TILE_PLATEFORME_DEBUT = 130;
const int TILE_PLATEFORME_FIN = 131;
 
// Tiles pentes à 26.5° ; BenH = de BAS en HAUT ; HenB = De HAUT en BAS
const int TILE_PENTE_26_BenH_1 = 69;
const int TILE_PENTE_26_BenH_2 = 70;
const int TILE_PENTE_26_HenB_1 = 71;
const int TILE_PENTE_26_HenB_2 = 72;
 
 
};
#endif

 

   Voilà, donc au niveau des variables, vous remarquerez que :

- on a ajouté une variable de type sf::Font font qui contiendra notre police de caractères (font en anglais): Gentium,

- et on a ajouté 2 Textures et 2 Sprites pour contenir les 2 images du HUD que vous avez téléchargées ci-dessus.

   Et c'est tout ! cheeky

 

   Au niveau des fonctions, maintenant, on a ajouté les prototypes de nos 2 nouvelles fonctions :

- drawText() qui se chargera d'écrire une chaîne de caractères (string) à l'écran,

- et drawHUD() qui affichera le HUD, notamment en faisant appel à la fonction ci-dessus.

   On met ensuite à jour notre constructeur, dans le fichier map.cpp, afin de charger la font et les nouvelles images du HUD au sein de la classe :

 

Fichier : map.cpp : Remplacer la fonction précédente par :

//Constructeur
Map::Map()
{
//Chargement des ressources graphiques
//Chargement du background
if (!backgroundTexture.loadFromFile("graphics/background.png"))
{
// Erreur
cout << "Erreur durant le chargement de l'image de background." << endl;
}
else
background.setTexture(backgroundTexture);
 
//Chargement des 2 tilesets n°1
if (!tileSet1Texture.loadFromFile("graphics/tileset1.png"))
{
// Erreur
cout << "Erreur durant le chargement de l'image du tileset 1." << endl;
}
else
tileSet1.setTexture(tileSet1Texture);
 
if (!tileSet1BTexture.loadFromFile("graphics/tileset1b.png"))
{
// Erreur
cout << "Erreur durant le chargement de l'image du tileset 1b." << endl;
}
else
tileSet1B.setTexture(tileSet1BTexture);
 
//Chargement de la police Gentium
if (!font.loadFromFile("font/GenBasB.ttf"))
{
// Erreur
cout << "Erreur durant le chargement de la police." << endl;
}
 
//Chargement du HUD
if (!HUDEtoilesTexture.loadFromFile("graphics/stars.png"))
{
// Erreur
cout << "Erreur durant le chargement de l'image du HUD Etoiles." << endl;
}
else
HUDEtoiles.setTexture(HUDEtoilesTexture);
 
if (!HUDViesTexture.loadFromFile("graphics/life.png"))
{
// Erreur
cout << "Erreur durant le chargement de l'image du HUD Vies." << endl;
}
else
HUDVies.setTexture(HUDViesTexture);
 
 
//Autres variables
mapTimer = TIME_BETWEEN_2_FRAMES * 3;
tileSetNumber = 0;
level = 1;
startX = startY = 0;
}
 

   Rien de compliqué. wink On passe au code, dans le fichier map.cpp :

Fichier : map.cpp : Rajouter les fonctions :

void Map::drawText(RenderWindow &window, string message, int size, int x, int y, Color color)
{
sf::Text text;
 
// choix de la police à utiliser
text.setFont(font); // font est un sf::Font
 
// choix de la chaîne de caractères à afficher
text.setString(message);
 
// choix de la taille des caractères
text.setCharacterSize(size); // exprimée en pixels, pas en points !
 
// choix de la couleur du texte
text.setColor(color);
 
//Positionne le texte
text.setPosition(x, y);
 
//Et le dessine
window.draw(text);
}
 
 
void Map::drawHud(Player &player, RenderWindow &window)
{
//Affiche le nombre de coeurs
//On crée une boucle pour afficher de 1 à 3 coeurs
//selon la vie, avec un décalage de 32 pixels
for (int i = 0; i < player.getLife(); i++)
{
// Calcul pour découper le tileset comme dans la fonction map.draw()
int ysource = TILE_POWER_UP_COEUR / 10 * TILE_SIZE;
int xsource = TILE_POWER_UP_COEUR % 10 * TILE_SIZE;
 
tileSet1.setPosition(Vector2f(60 + i * 32, 20));
tileSet1.setTextureRect(sf::IntRect(xsource, ysource, TILE_SIZE, TILE_SIZE));
window.draw(tileSet1);
}
 
/* Affiche le nombre de vies en bas à droite - Adaptation à la fenêtre auto */
HUDVies.setPosition(SCREEN_WIDTH - 120, SCREEN_HEIGHT - 70);
window.draw(HUDVies);
 
//Pour afficher le nombre de vies, on utilise notre fonction créée précédemment pour écrire en noir
//et en blanc afin de surligner le texte et de le rendre plus
//visible
drawText(window, "x " + to_string(player.getVies()), 28, SCREEN_WIDTH - 80, SCREEN_HEIGHT - 60, Color::Black);
drawText(window, "x " + to_string(player.getVies()), 28, SCREEN_WIDTH - 82, SCREEN_HEIGHT - 62, Color::White);
 
/* Affiche le nombre d'étoiles en haut à gauche */
HUDEtoiles.setPosition(60, 60);
window.draw(HUDEtoiles);
 
drawText(window, to_string(player.getEtoiles()), 28, 100, 57, Color::Black);
drawText(window, to_string(player.getEtoiles()), 28, 98, 55, Color::White);
}
 

      La fonction drawText()

   Vous remarquerez qu'elle prend un bon paquet d'arguments, mais ce n'est pas compliqué en fait ! wink

- window correspond à notre fenêtre, pour pouvoir y dessiner, comme d'habitude.

message correspond au texte à afficher / écrire. C'est une chaîne de caractères, ou string en anglais.

- size correspond à la taille du texte à écrire.

x et y sont les coordonnées à l'écran où on doit écrire.

- et color correspond à la couleur du texte !

   Pour le reste, les commentaires expliquent son fonctionnement qui n'a rien de sorcier. La SFML nous mâche, en effet, le plus gros du boulot ! wink

 

      La fonction drawHUD()

   La fonction est déjà pas mal commentée :

- on affiche d'abord le nombre de coeurs à l'aide d'une boucle. Et on pique l'image dans notre tileset (comme ça on économise un peu de mémoire cheeky).

- on affiche ensuite l'icône vie et on écrit le nombre de vies à côté.

- idem pour les étoiles.

Vous noterez qu'on écrit 2 fois le texte avec un léger décalage, en blanc et en noir. Cela pour deux raisons :
      - 1. C'est plus joli,
      - 2. Le texte reste toujours lisible, que le fond soit clair ou foncé !

    Il ne nous manque plus qu'à mettre à jour la boucle principale de notre main() pour appeler la fonction drawHUD() wink:

 

Fichier : main.cpp : Modifier :

/** DESSIN - DRAW **/
//On dessine tout
window.clear();
 
//On affiche le background
map.drawBackground(window);
 
// Affiche la map de tiles : layer 2 (couche du fond)
map.draw(2, window, monster);
 
// Affiche la map de tiles : layer 1 (couche active : sol, etc.)
map.draw(1, window, monster);
 
// Affiche le joueur
player.draw(map, window);
 
//On affiche les monstres un par un
for (int i = 0; i < map.getNombreMonstres(); i++)
{
monster[i].draw(map, window);
}
 
// Affiche la map de tiles : layer 3 (couche en foreground / devant)
map.draw(3, window, monster);
 
//Affichage du HUD
map.drawHud(player, window);
 
window.display();

   Voilà, on compile et on lance le programme ! wink   

   Le HUD s'affiche maintenant devant vos yeux ébahis ! indecision

   Argh !! Mais si je perds plein de vies, je passe dans le négatif !?! surprise Qu'est-ce que c'est que ça ?!? angry

   Rassurez-vous, c'est normal ! wink Nous n'avons pas encore programmer les menus et nous n'avons donc pas encore de Game Over, mais ça va venir ! laugh

 

   Je vous dis donc à bientôt pour le chapitre 14 ! angel

                                                                            Jay 

 

 

This site uses cookies to enable you to log in. We do not store or sell any personal data. By continuing to use this website, you agree to their use. Thanks!