07/05/2023 : Malheureusement, suite à un manque de financement et à des échéances prochaines impliquant de refaire TOUT le site en l'adaptant à une nouvelle plateforme pour pallier les risques croissants de sécurité, il est pour l'instant prévu que le site ferme prochainement ses portes...
 
13/06/2023 : Finalement, le site a été refinancé pour une nouvelle année complète. En l'état, il est fonctionnel mais notre hébergeur ne nous permet pas une mise à jour vers Joomla 4 ou php 8 (il a été racheté et n'est plus que l'ombre de lui-même...). Cela nous laisse cependant un peu de temps pour trouver une solution.

 

 
 



Créons un jeu de plateformes de A à Z !




Tutoriel présenté par : Jérémie F. Bellanger

Dernière mise à jour : 13 septembre 2011

Difficulté :  




16. Afficher le HUD : vies et étoiles ramassées


    Il manque quand même quelque chose d'important à notre jeu maintenant : l'affichage du HUD - Head Up Display, ou affichage tête haute en français. En effet, il faut bien que le joueur sache combien de vies il a et combien de power-ups il a ramassé !

    Dans notre cas, on va afficher le nombre de vies de notre super lapin (et donc créer une variable vies) et le nombre de petites étoiles ramassées. Bon, pour l'instant, on ne peut pas ramasser de petites étoiles (ce sera l'objet d'un prochain chapitre), mais au moins ce nombre sera affiché !


    Dernière chose, pour afficher du texte en SDL, nous allons avoir besoin d'une nouvelle bibliothèque (library) : SDL_TTF !
   

    Allez, c'est parti ! 
   


Résultat à la fin de ce chapitre : le HUD s'affiche désormais !


A. Avant de commencer

    Bon, commençons par installer SDL_TTF !

    Vous trouverez comment la télécharger dans la première page du tuto (si vous ne l'avez toujours pas fait !).

    Une fois téléchargé, dézippez le fichier, copiez le contenu des dossiers lib et include dans les dossiers correspondants de la SDL pour les retrouver plus facilement.
    Copiez ensuite les libs : libfreetype-3.dll, SDL_ttf.dll et zlib1.dll dans le dossier Aron de votre projet.

    Ensuite, il ne reste plus qu'à configurer votre projet. Allez dans le menu Project / Build Options. Là, dans l'onglet Linker, cliquez sur Add et sélectionnez le fichier SDL_ttf.lib (suivant là où vous l'avez mis ). Cliquez ensuite sur OK (sans oublier de répéter l'opération pour debug et release, suivant ce que vous souhaitez compiler, bien sûr).

    Et voilà, on va maintenant modifier notre fichier defs.h pour que le compilateur puisse trouver le fichier en-tête contenant les prototypes des fonctions de SDL_TTF :

Nom du fichier : defs.h


   #include <stdio.h>
   #include <string.h>
   #include <stdlib.h>
   #include <math.h>
   #include <SDL/SDL.h>
   /* On inclut les libs supplémentaires */
   #include <SDL/SDL_image.h>
   #include <SDL/SDL_ttf.h>

   /* Taille de la fenêtre / résolution en plein écran */
   #define SCREEN_WIDTH 640
   #define SCREEN_HEIGHT 480
   .....
         

    Et voilà, le tour est joué ! Maintenant, si vous avez envie de vous amuser un peu à manipuler cette lib pour vous entraîner, je vous rappelle cet excellent tuto du site du zéro.

   Autre chose, avant de nous lancer tête bêche dans le code ! Il nous faut 2 dessins pour notre HUD ! 

    Heureusement, je suis généreux et je vous les offre ci-dessous !


    Copiez-les simplement dans le répertoire graphics sous leur nom respectif (comme d'habitude quoi !) :


life.png


stars.png

    Sans oublier non plus, une police de caractères (font). Vous pouvez prendre celle que vous voulez. Pour ma part, je vous propose Gentium Basic qui est une openfont, libre de droit. Vous pourrez donc l'utiliser dans vos jeux à condition de l'ajouter dans les crédits bien sûr !


    Dézippez le fichier et copiez le contenu de l'archive dans le dossier Aron. Vous obtiendrez ainsi un nouveau dossier font, contenant notre police.
    Bon, passons maintenant au code !


B. Ajoutons les fonctions nécessaires à la gestion du texte

    Bon, on va commencer par créer une variable pour contenir notre police de caractères (font) !


Nom du fichier : main.h


   #include "structs.h"

   /* Prototypes des fonctions utilisées */

   extern void init(char *);
   extern void cleanup(void);
   extern void getInput(void);
   extern void draw(void);
   extern void loadGame(void);
   extern void delay(unsigned int frameLimit);
   extern void updatePlayer(void);
   extern void initializePlayer(void);
   extern void updateMonsters(void);


   /* Déclaration des structures globales utilisées par le jeu */

   Input input;
   Gestion jeu;
   Map map;
   GameObject player;
   GameObject monster[MONSTRES_MAX];
   /* Déclaration de notre police de caractères */
   TTF_Font *font;

         

    On va ensuite rajouter l'initialisation de notre lib après celle de la SDL puis on va charger notre police de caractères.


Nom du fichier : init.c


  void init(char *title)
{
    /* Initialise SDL Video */

    if (SDL_Init(SDL_INIT_VIDEO ) < 0)
    {
        printf("Could not initialize SDL: %s\n", SDL_GetError());

        exit(1);
    }


    jeu.screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, SDL_HWPALETTE|SDL_DOUBLEBUF);

    if (jeu.screen == NULL)
        {
            printf("Couldn't set screen mode to %d x %d: %s\n", SCREEN_WIDTH, SCREEN_HEIGHT, SDL_GetError());
            exit(1);
        }

    /* Titre de la fenetre */

    SDL_WM_SetCaption(title, NULL);


    /* Cache le curseur de la souris */

    SDL_ShowCursor(SDL_DISABLE);
   
   
    /* Initialise SDL_TTF */

    if (TTF_Init() < 0)
    {
        printf("Couldn't initialize SDL TTF: %s\n", SDL_GetError());

        exit(1);
    }

    /* Charge la police en 32 points (taille) */

    font = loadFont("font/GenBasB.ttf", 32);

}

         


    Sans oublier de faire le ménage à la fin en libérant la mémoire allouée à notre police et en fermant la lib !

    Cela dit, en passant, regardez bien cette fonction, car il lui manque quelque chose (et c'est pas la seule malheureusement)... Ahah !

    En fait, on a fait quelques bêtises dans les chapitres précédents (et vous ne vous en serez sans doute même pas rendu compte ! ). Mais je l'ai fait exprès, pour pouvoir vous en parler dans le prochain chapitre : les fuites de mémoire !
(Oui, c'est ça, dis plutôt que tu t'es planté, oui ! - Mais, non, ça a un but pédagogique ! Je le jure ! ).


Nom du fichier : init.c


  void cleanup()
{

    /* Libère l'image du background */

    if (map.background != NULL)
    {
        SDL_FreeSurface(map.background);
    }


    /* Libère l'image du tileset */

    if (map.tileSet != NULL)
    {
        SDL_FreeSurface(map.tileSet);
    }

    /* Close the font */

    closeFont(font);


    /* Close SDL_TTF */

    TTF_Quit();

    /* Quitte la SDL */
    SDL_Quit();

}

     

    Sans oublier l'en-tête comme d'habitude :


Nom du fichier : init.h


  #include "structs.h"

   /* Prototypes des fonctions utilisées */
   extern SDL_Surface *loadImage(char *name);
   extern void loadMap(char *name);
   extern void closeFont(TTF_Font *font);
   extern TTF_Font *loadFont(char *, int);

   extern Gestion jeu;
   extern Map map;
  extern TTF_Font *font;
   

    Bon, comme vous n'aurez pas manqué de le remarquer, les fonctions loadFont et closeFont n'existent pas encore. Il va donc falloir les ajouter. Pour cela, nous allons créer deux nouveaux fichiers : font.c et font.h (comme d'habitude en faisant New/Empty File) .

    Dans le même temps, nous allons créer une fonction drawString() qui prendra comme argument une chaîne de caractères (string), des coordonnées où blitter et la police de caractères voulue. Cette fonction génèrera alors une image temporaire à l'aide de SDL_TTF à partir de notre chaîne de caractères et la blittera aux coordonnées indiquées. Enfin, elle libèrera la mémoire de notre image temporaire dont nous n'aurons plus besoin !

    Je vous laisse regarder :


Nom du fichier : font.c


 #include "font.h"

TTF_Font *loadFont(char *name, int size)
{
    /* Utilise SDL_TTF pour charger la police à la taille désirée */

    TTF_Font *font = TTF_OpenFont(name, size);

    if (font == NULL)
    {
        printf("Failed to open Font %s: %s\n", name, TTF_GetError());

        exit(1);
    }

    return font;
}


void closeFont(TTF_Font *font)
{
    /* Ferme la police quand on n'en a plus besoin (avant de quitter) */

    if (font != NULL)
    {
        TTF_CloseFont(font);
    }
}


void drawString(char *text, int x, int y, TTF_Font *font)
{
    SDL_Rect dest;
    SDL_Surface *surface;
    SDL_Color foregroundColor;

    /* On choisit d'écrire le texte en noir */
    foregroundColor.r = 0;
    foregroundColor.g = 0;
    foregroundColor.b = 0;


    /* On utilise SDL_TTF pour générer une SDL_Surface à partir d'une chaîne de caractères (string) */

    surface = TTF_RenderUTF8_Blended(font, text, foregroundColor);


    if (surface == NULL)
    {
        printf("Couldn't create String %s: %s\n", text, SDL_GetError());

        return;
    }

    /* On blitte cette SDL_Surface à l'écran */

    dest.x = x;
    dest.y = y;
    dest.w = surface->w;
    dest.h = surface->h;

    SDL_BlitSurface(surface, NULL, jeu.screen, &dest);

    /* On libère la SDL_Surface temporaire (pour éviter les fuites de mémoire - cf. chapitre dédié) */
    SDL_FreeSurface(surface);
}

         


    Voilà, il suffit maintenant de compléter notre nouvel en-tête :

Nom du fichier : font.h


   #include "structs.h"

   extern Gestion jeu;
   extern TTF_Font *font;
         

   Si vous compilez maintenant, vous verrez que tout est OK. Notre jeu est apte à gérer du texte mais il ne le fait pas encore !
    Alors qu'est-ce qu'on attend ?



C. L'affichage du HUD (enfin !)


    Eh oui ! Avec tout ça, on en a presque oublié notre HUD ! 
    Il faut dire qu'installer une nouvelle lib prend du temps...

    Bon, maintenant, que c'est fait, nous allons créer 2 nouvelles variables dont nous allons afficher la valeur à l'écran : vies et étoiles.
    Pour l'instant, ces variables resteront fixes, on s'occupera de les changer plus tard ! (On a déjà assez de boulot comme ça, non mais ! ).
    On va aussi créer 2 SDL_Surface qui contiendront les sprites de notre HUD.

Nom du fichier : structs.h


  /* Structure pour gérer le niveau (à compléter plus tard) */

typedef struct Gestion
{

    SDL_Surface *screen;
    int nombreMonstres;

    //HUD
    SDL_Surface *HUD_vie, *HUD_etoiles;
    int vies, etoiles;

} Gestion;

         

    Bien sûr, on va les initialiser dans la fonction loadGame(), et charger les sprites correspondants :

Nom du fichier : init.c


  void loadGame(void)
{

    /* Charge l'image du fond et le tileset */
    map.background = loadImage("graphics/background.png");
    map.tileSet = loadImage("graphics/tileset.png");

    loadMap("map/map1.txt");
   
    /* On initialise les variables du jeu */
    jeu.vies = 3;
    jeu.etoiles = 0;

    /* On charge le HUD */
    jeu.HUD_vie = loadImage("graphics/life.png");
    jeu.HUD_etoiles = loadImage("graphics/stars.png");


}

         

    On commencera donc avec 3 vies et 0 étoiles. Classique, quoi ?!
    Maintenant, on n'oublie pas de libérer nos deux nouvelles variables quand on quitte (on verra bientôt pourquoi c'est important ) :

Nom du fichier : init.c


  void cleanup()
{

    /* Libère l'image du background */

    if (map.background != NULL)
    {
        SDL_FreeSurface(map.background);
    }


    /* Libère l'image du tileset */

    if (map.tileSet != NULL)
    {
        SDL_FreeSurface(map.tileSet);
    }
   
    //Libère le HUD
    if (jeu.HUD_etoiles != NULL)
    {
        SDL_FreeSurface(jeu.HUD_etoiles);
    }
    if (jeu.HUD_vie != NULL)
    {
        SDL_FreeSurface(jeu.HUD_vie);
    }

    /* Close the font */
    closeFont(font);


    /* Close SDL_TTF */
    TTF_Quit();

    /* Quitte la SDL */
    SDL_Quit();

}

         

    Il ne nous reste plus maintenant qu'à créer une fonction DrawHud() et le tour sera joué !

Nom du fichier : draw.c


  void drawHud(void)
{
    //On crée une varuiable qui contiendra notre texte (jusqu'à 200 caractères, y'a de la marge ;) ).
    char text[200];


    /* Affiche le nombre de vies en bas à droite */
    drawImage(jeu.HUD_vie, 480, 410);
    //Pour afficher le nombre de vies, on formate notre string pour qu'il prenne la valeur de la variable
    sprintf(text, "%d", jeu.vies);
    //Puis on utilise notre fonction créée précédemment
    drawString(text, 560, 420, font);

    /* Affiche le nombre d'étoiles en haut à gauche */
    drawImage(jeu.HUD_etoiles, 60, 60);
    sprintf(text, "%d", jeu.etoiles);
    drawString(text, 100, 57, font);

}
         

    Cette fonction est plutôt simple : on affiche nos deux sprites pour le HUD et on affiche le texte correspondant à nos variables à côtés.

    Il est à noter que les coordonnées de blittage ont été obtenues par tâtonnements successifs jusqu'à trouver les valeurs idéales pour que ça fasse joli. Mais libre à vous de créer un HUD qui vous ressemble !

    Voilà, on met maintenant à jour notre fonction draw() pour qu'elle prenne en charge notre nouvelle fonction :



Nom du fichier : draw.c


  void draw(void)
{

    int i;

    /* Affiche le fond (background) aux coordonnées (0,0) */
    drawImage(map.background, 0, 0);

    /* Affiche la map de tiles */
    drawMap();

    /* Affiche le joueur */
    drawAnimatedEntity(&player);

    /* Affiche les monstres */
    for(i = 0 ; i < jeu.nombreMonstres ; i++)
    {
        drawAnimatedEntity(&monster[i]);
    }
   
    //On affiche le HUD par-dessus tout le reste
    drawHud();

    /* Affiche l'écran */
    SDL_Flip(jeu.screen);

    /* Delai */

    SDL_Delay(1);

}

         

    Et on met à jour notre en-tête :

Nom du fichier : draw.h


  #include "structs.h"

/* Prototypes des fonctions utilisées */
extern void drawMap(void);
extern void drawAnimatedEntity(GameObject *entity);
extern void drawHud(void);
extern void drawString(char *text, int x, int y, TTF_Font *font);


/* Structures globales */
extern Gestion jeu;
extern Map map;
extern GameObject player;
extern GameObject monster[];
extern TTF_Font *font;
         


    Eh voilà ! Si on compile, le HUD s'affiche désormais ! Elle est pas belle la vie ?

    Maintenant, avant d'aborder le prochain chapitre, je vais vous demander d'ouvrir les gestionnaire des tâches de Windows en faisant un clic droit sur la barre de menu en bas (traditionnellement) de votre écran. Démarrez le jeu Aron, et sélectionnez-le dans le gestionnaire des tâches. Vous verrez à droite la quantité de mémoire utilisée par notre programme.

    Jouez un peu, et vous verrez que cette valeur ne cesse d'augmenter ! Mais comment est-ce possible !?  Et bien tout simplement parce que notre programme a des fuites de mémoire !

    C'est grave, docteur ?  Bah, oui, au bout d'un moment ça risque de prendre toute la mémoire de votre ordi et de le faire ramer ou même planter...  La solution va donc consister à trouver la source de ces fuites et à les supprimer ! Et c'est ce qu'on va voir dans le prochain chapitre ! Comme ça, vous serez ensuite parés pour repérer les fuites dans vos propres programmes !


   


   




 

 

 

Connexion

CoalaWeb Traffic

Today9
Yesterday232
This week1035
This month3328
Total1742535

20/04/24