Big Tuto SDL 2 : Rabidja v. 3.0

Chapitre 18 : Ajoutons des menus !

 

Tutoriel présenté par : Jérémie F. Bellanger (Jay81)
Ecriture : 11 novembre 2014

Dernière mise à jour : 11 novembre 2015

 

      Prologue

   Notre jeu prend maintenant de l'ampleur et a de l'allure, mais le problème, c'est qu'on n'a pas de Game Over, ni de menus pour gérer le jeu ! surprise

   Et comment dire... frown Un jeu sans menu, ça fait vraiment pas pro ! angry Et ce serait dommage de gâcher un bon jeu à cause d'une absence de menus, ou même de menus bâclés ! wink

   C'est pour cela que nous allons voir dans ce chapitre comment faire pour ajouter des menus ! angel ?   

   Votre mission, si vous l'acceptez (et vous avez intérêt, hein !? laugh) va être de créer un menu Start, auquel on reviendra quand notre lapin décèdera, et qui nous permettra en sus de sélectionner le niveau de départ (ce sera mieux si on en rajoute 99, comme on n'a pas de sauvegarde wink) !

   Cela dit, comme le joueur voudra sans doute faire des pauses de temps en temps (c'est mieux pour sa santé mentale ! cheeky), on va aussi implémenter menu pause qui nous permettra également de retourner à l'écran-titre, pour changer de niveau, au besoin (ouh, le tricheur ! laugh). 

   Allez, on est parti !

 

      Nouveaux fichiers à ajouter au projet

   Avant de commencer, il va nous falloir ajouter une nouvelle image pour l'écran-titre. Et tant qu'à faire, autant que celle-ci ait de la gueule ! wink

   Enregistrez donc l'image suivant dans le dossier graphics de votre projet, sous le nom title.pngangel

 

title.png

      Le code

    Pour pouvoir rajouter des menus à notre jeu, il faut en fait que celui-ci gère plusieurs états. Le premier état, celui que nous avons pour l'instant est l'état "onGame", ou "en jeu" (même si on aura pas besoin de variable pour l'indiquer, en fait wink). Ce qui veut dire que le programme exécute le jeu normalement. Nous allons lui rajouter un deuxième état : "onMenu", soit "dans un menu", à l'aide d'une nouvelle variable, et nous enregistrerons le type de menu à afficher dans une autre variable grâce à une nouvelle énum que l'on va ajouter à notre fichier defs.h :  

Fichier : defs.h : Modifier :

//Une enum pour la gestion du menu.
enum
{
START,
PAUSE
}; 

 

   On va ensuite créer les fonctions qui gèreront nos menus Start et Pause. Pour éviter de mélanger les menus avec le reste du jeu, on va encore créer un nouveau fichier : menu.c.

   C'est ce fichier qui contiendra nos nouvelles variables, à savoir :
- onMenu : qui vaudra 0 si on est en jeu et 1 si on est dans un menu,
- menuType : qui utilisera les valeurs de notre ENUM pour nous dire dans quel menu on est,
- titlescreen : qui contiendra l'image de notre écran-titre. Notez qu'on ne la chargera qu'une fois au début du jeu et on la déchargera à la fin, comme tous nos autres fichiers graphiques. Je vous rappelle que cette pratique est grandement conseillée. Evitez autant que faire se peut les chargements disques in-game. wink
- choice : sera une variable outil qui nous permettra de savoir quel item d'un menu on sélectionnera.

 

   Logiquement, le début de notre fichier va donc contenir une fonction :
- getOnMenu() pour savoir de l'extérieur la valeur de la variable onMenu,
- getMenuType() pour connaître le type de menu,
- setOnMenu() pour changer l'état du jeu (en mode menu ou pas) et indiquer le menu à afficher, le cas échéant,
- initMenus() qui chargera le titlescreen,
- et enfin cleanMenus() qui le déchargera.

 

   Et ensuite, pour gérer chacun de nos menus, on aura besoin de 2 fonctions classiques : update() pour le mettre à jour et draw() pour le dessiner. wink

   Mais que vont faire nos menus exactement ? surprise

   Notre menu Start va afficher l'écran-titre de notre jeu, et proposer deux options : Start et Quit (oui, je sais, c'est super simpliste mais vous ferez des super menus compliqués plus tard, quand vous aurez compris les bases ! cheeky). Mais notez également qu'on va proposer au joueur de choisir son niveau de départ. On devra donc afficher à côté de Start, le numéro du niveau de départ et pouvoir le modifier à l'aide des flèches gauche / droite du clavier (ou avec le gamepad). wink

   Notre menu Pause s'affichera si on presse Enter (ou Start sur le gamepad), stoppera le jeu et proposera soit de continuer, soit de quitter la partie.

   Voilà pour la théorie, alors place au code ! angel

   Créez le nouveau fichier menu.c si ce n'est déjà fait et copiez-y le code suivant :

 

Fichier : menu.c : Créer le fichier et y copier :

#include "prototypes.h"
 
 
 
//Gestion des menus
int onMenu, menuType, choice;
SDL_Texture *titlescreen;
 
 
int getOnMenu(void)
{
return onMenu;
}
 
int getMenuType(void)
{
return menuType;
}
 
void setOnMenu(int valeur, int type)
{
onMenu = valeur;
menuType = type;
}
 
void initMenus(void)
{
titlescreen = loadImage("graphics/title.png");
}
 
void cleanMenus(void)
{
// Libère la texture de l'écran-titre
if (titlescreen != NULL)
{
SDL_DestroyTexture(titlescreen);
titlescreen = NULL;
}
}
 
 
void updateStartMenu(Input *input)
{
//Si on appuie sur BAS
if (input->down == 1)
{
//Si choice = O (il est sur start), on le met à 1 (quit)
if (choice == 0)
choice++;
 
input->down = 0;
}
 
//Si on appuie sur HAUT
if (input->up == 1)
{
//Si choice = 1 (il est sur Quit), on le met à 0 (Start)
if (choice == 1)
choice--;
 
input->up = 0;
}
 
//Choix du level
if (input->right == 1)
{
//Si choice = 1 (il est sur Quit), on le met à 0 (Start)
if (getLevel() >= LEVEL_MAX)
SetValeurDuNiveau(1);
else
SetValeurDuNiveau(getLevel() + 1);
 
input->right = 0;
}
 
if (input->left == 1)
{
//Si choice = 1 (il est sur Quit), on le met à 0 (Start)
if (getLevel() <= 1)
SetValeurDuNiveau(LEVEL_MAX);
else
SetValeurDuNiveau(getLevel() - 1);
 
input->left = 0;
}
 
 
//Si on appuie sur Enter ou A (manette Xbox 360) et qu'on est sur Start, on recharge le jeu et on quitte l'état menu
if (input->enter || input->jump)
{
if (choice == 0)
{
resetCheckpoint();
initializePlayer(1);
changeLevel();
 
/* On réinitialise les variables du jeu */
setNombreDeVies(3);
setNombreDetoiles(0);
onMenu = 0;
}
 
//Sinon, on quitte le jeu
else if (choice == 1)
{
exit(0);
}
 
input->enter = 0;
input->jump = 0;
}
 
}
 
 
 
void updatePauseMenu(Input *input)
{
 
//Si on appuie sur BAS
if (input->down == 1)
{
//Si choice = O (il est sur start), on le met à 1 (quit)
if (choice == 0)
choice++;
 
input->down = 0;
}
 
//Si on appuie sur HAUT
if (input->up == 1)
{
//Si choice = 1 (il est sur Quit), on le met à 0 (Start)
if (choice == 1)
choice--;
 
input->up = 0;
}
 
//Si on appuie sur Enter ou A (manette Xbox 360) et qu'on est sur Start, on recharge le jeu et on quitte l'état menu
if (input->enter || input->jump)
{
if (choice == 0)
{
//Si on appuie sur Enter on quitte l'état menu
onMenu = 0;
}
 
//Sinon, on quitte le jeu
else if (choice == 1)
{
choice = 0;
menuType = START;
}
 
input->enter = 0;
input->jump = 0;
}
 
}

 

    Mais, ce code ne contient que les fonctions d'update ! et pas celles de draw ! surprise

   Tout juste, Auguste ! wink C'est simplement parce que, là encore, nos fonctions vont être un peu différentes selon l'IDE que vous utilisez : Code::Blocks ou Visual Studio. wink Vous les ajouterez donc ci-dessous, selon votre IDE de pédilection.

   Mais avant cela, revenons rapidement sur nos fonctions d'update.

   Comme vous pouvez le voir, le code n'est pas très compliqué. wink

   Pour updateStartMenu(), on change simplement la valeur du niveau de départ en appuyant sur Gauche/Droite à la 1ère ligne du menu, et on l'affiche. Le jeu démarrera ainsi à ce niveau-là. La seconde ligne permet de quitter le jeu proprement (c'est plus pro qu'avec Escape wink).

   Le code d'updatePauseMenu() reprend grosso modo celui de l'écran-titre avec deux possibilités : soit on reprend le jeu, soit on retourne à l'écran-titre en changeant simplement le menuTypecool

   Vous remarquerez aussi qu'on remet systématiquement les inputs à 0, pour une raison simple : sinon on valide tous les menus à la suite, et on passe de l'un à l'autre en un éclair (vous pouvez essayer, pour voir indecision). Grâce à cette technique, le joueur sera obligé de lâcher le bouton et de réappuyer s'il veut valider une seconde fois.

 

   Passons maintenant au code des fonctions de dessin (à choisir selon votre IDE) : 

 

Version Visual Studio 2013

Fichier : menu.c : Rajouter (Visual Studio seulement) :

void drawStartMenu(void)
{
 
//On crée une variable qui contiendra notre texte
char text[200];
 
//On affiche l'écran-titre
drawImage(titlescreen, 0, 0);
 
//Si l'option n'est pas en surbrillance, on l'affiche normalement
if (choice != 0)
{
sprintf_s(text, sizeof(text), "START: Lvl %d", getLevel());
//Ombrage en noir
drawString(text, 375, 252, 0, 0, 0, 255);
drawString(text, 373, 250, 255, 255, 255, 255);
}
if (choice != 1)
{
sprintf_s(text, sizeof(text), "QUIT");
//Ombrage en noir
drawString(text, 425, 292, 0, 0, 0, 255);
drawString(text, 422, 290, 255, 255, 255, 255);
}
 
//Si l'option est en surbrillance, on change la couleur
if (choice == 0)
{
sprintf_s(text, sizeof(text), "START: Lvl %d", getLevel());
//Ombrage en noir
drawString(text, 375, 252, 0, 0, 0, 255);
drawString(text, 373, 250, 255, 255, 0, 255);
}
else if (choice == 1)
{
sprintf_s(text, sizeof(text), "QUIT");
//Ombrage en noir
drawString(text, 425, 292, 0, 0, 0, 255);
drawString(text, 422, 290, 255, 255, 0, 255);
}
 
}
 
 
 
void drawPauseMenu(void)
{
char text[200];
 
//On écrit PAUSE
sprintf_s(text, sizeof(text), "** PAUSE **");
drawString(text, 322, 200, 0, 0, 0, 255);
drawString(text, 320, 198, 255, 255, 255, 255);
 
 
//Si l'option n'est pas en surbrillance, on l'affiche normalement
if (choice != 0)
{
sprintf_s(text, sizeof(text), "Continue");
//Ombrage en noir
drawString(text, 346, 252, 0, 0, 0, 255);
drawString(text, 344, 250, 255, 255, 255, 255);
}
if (choice != 1)
{
sprintf_s(text, sizeof(text), "Exit");
//Ombrage en noir
drawString(text, 386, 292, 0, 0, 0, 255);
drawString(text, 384, 290, 255, 255, 255, 255);
}
 
 
//Si l'option est en surbrillance, on change la couleur
if (choice == 0)
{
sprintf_s(text, sizeof(text), "Continue");
//Ombrage en noir
drawString(text, 346, 252, 0, 0, 0, 255);
drawString(text, 344, 250, 255, 255, 0, 255);
}
else if (choice == 1)
{
sprintf_s(text, sizeof(text), "Exit");
//Ombrage en noir
drawString(text, 386, 292, 0, 0, 0, 255);
drawString(text, 384, 290, 255, 255, 0, 255);
}
 
} 

 

Version CodeBlocks

Fichier : menu.c : Rajouter (Code::Blocks seulement) :

void drawStartMenu(void)
{
 
//On crée une variable qui contiendra notre texte
char text[200];
 
//On affiche l'écran-titre
drawImage(titlescreen, 0, 0);
 
//Si l'option n'est pas en surbrillance, on l'affiche normalement
if (choice != 0)
{
sprintf(text, "START: Lvl %d", getLevel());
//Ombrage en noir
drawString(text, 375, 252, 0, 0, 0, 255);
drawString(text, 373, 250, 255, 255, 255, 255);
}
if (choice != 1)
{
sprintf(text, "QUIT");
//Ombrage en noir
drawString(text, 425, 292, 0, 0, 0, 255);
drawString(text, 422, 290, 255, 255, 255, 255);
}
 
//Si l'option est en surbrillance, on change la couleur
if (choice == 0)
{
sprintf(text, "START: Lvl %d", getLevel());
//Ombrage en noir
drawString(text, 375, 252, 0, 0, 0, 255);
drawString(text, 373, 250, 255, 255, 0, 255);
}
else if (choice == 1)
{
sprintf(text, "QUIT");
//Ombrage en noir
drawString(text, 425, 292, 0, 0, 0, 255);
drawString(text, 422, 290, 255, 255, 0, 255);
}
 
}
 
 
 
void drawPauseMenu(void)
{
char text[200];
 
//On écrit PAUSE
sprintf(text, "** PAUSE **");
drawString(text, 322, 200, 0, 0, 0, 255);
drawString(text, 320, 198, 255, 255, 255, 255);
 
 
//Si l'option n'est pas en surbrillance, on l'affiche normalement
if (choice != 0)
{
sprintf(text, "Continue");
//Ombrage en noir
drawString(text, 346, 252, 0, 0, 0, 255);
drawString(text, 344, 250, 255, 255, 255, 255);
}
if (choice != 1)
{
sprintf(text, "Exit");
//Ombrage en noir
drawString(text, 386, 292, 0, 0, 0, 255);
drawString(text, 384, 290, 255, 255, 255, 255);
}
 
//Si l'option est en surbrillance, on change la couleur
if (choice == 0)
{
sprintf(text, "Continue");
//Ombrage en noir
drawString(text, 346, 252, 0, 0, 0, 255);
drawString(text, 344, 250, 255, 255, 0, 255);
}
else if (choice == 1)
{
sprintf(text, "Exit");
//Ombrage en noir
drawString(text, 386, 292, 0, 0, 0, 255);
drawString(text, 384, 290, 255, 255, 0, 255);
}
 
}

 

    Rien de bien compliqué là encore :
- on affiche l'écran-titre pour drawStartMenu() (le menu Pause, lui, laisse le jeu se dessiner en arrière-plan wink).
- on écrit les items de nos menus : en noir pour les éléments non sélectionnés, en couleur sinon et on utilise un ombrage noir pour rendre le texte plus lisible (comme précédemment avec le HUD).
   Passons donc à la mise à jour de notre main() :

 

Fichier : main.c : Remplacer le main() par :

int main(int argc, char *argv[])
{
unsigned int frameLimit = SDL_GetTicks() + 16;
int go;
 
// Initialisation de la SDL
init("Rabidja 3 - SDL 2 - www.meruvia.fr");
 
// Chargement des ressources (graphismes, sons)
loadGame();
 
/* On initialise le joueur */
initializePlayer(1);
 
// Appelle la fonction cleanup à la fin du programme
atexit(cleanup);
 
go = 1;
 
// Boucle infinie, principale, du jeu
while (go == 1)
{
 
//Gestion des inputs et du joystick
gestionInputs(&input);
 
//Si on n'est pas dans un menu
if (getOnMenu() == 0)
{
/* On met à jour le jeu */
updatePlayer(&input);
updateMonsters();
doPlateforme();
}
else
{
if (getMenuType() == START)
updateStartMenu(&input);
 
else if (getMenuType() == PAUSE)
updatePauseMenu(&input);
}
 
 
//Si on n'est pas dans un menu, on affiche le jeu
if (getOnMenu() == 0)
drawGame(0);
 
else
{
if (getMenuType() == START)
{
drawStartMenu();
SDL_RenderPresent(getrenderer());
SDL_Delay(1);
}
 
else if (getMenuType() == PAUSE)
drawGame(1);
}
 
// Gestion des 60 fps (1000ms/60 = 16.6 -> 16
delay(frameLimit);
frameLimit = SDL_GetTicks() + 16;
}
 
// On quitte
exit(0);
 
}

  

   Vous l'aurez remarqué, les changements se font dans le boucle principale de notre jeu :
- au niveau de l'update du jeu, on ne met à jour le jeu que si l'on n'est pas dans un menu (ça évite que le jeu tourne tout seul en arrière-plan quand on est en Pause oi à l'écran-titre wink).
- sinon, on met à jour le menu correspondant, selon les inputs détectées.
- pour la fonction draw() : on dessine le jeu sauf si on est à l'écrant-titre (pour rappel : en Pause, le jeu s'affiche toujours, figé, en arrière-plan).

   Passons maintenant à la fonction drawGame() du fichier draw.c et rajoutons un appel à drawPauseMenu() qui affichera le menu de Pause si on est en Pause (logique, quoi ! wink).

 

Fichier : draw.c : Remplacer drawGame() par :

void drawGame(int pauseMenu)
{
int i;
 
// Affiche le fond (background) aux coordonnées (0,0)
drawImage(getBackground(), 0, 0);
 
/* Affiche la map de tiles : layer 2 (couche du fond) */
drawMap(2);
 
/* Affiche la map de tiles : layer 1 (couche active : sol, etc.)*/
drawMap(1);
 
/* Affiche le joueur */
drawPlayer();
 
/* Affiche les monstres */
for (i = 0; i < getMonsterNumber(); i++)
{
drawMonster(getMonster(i));
}
 
//Affiche les plateformes flottantes
drawPlateforme();
 
/* Affiche la map de tiles : layer 3 (couche en foreground / devant) */
drawMap(3);
 
//On affiche le HUD par-dessus tout le reste
drawHud();
 
//On affiche le menu Pause, si on est en Pause
if (pauseMenu)
drawPauseMenu();
 
// Affiche l'écran
SDL_RenderPresent(getrenderer());
 
// Délai pour laisser respirer le proc
SDL_Delay(1);
}

 

    Et puis, comme d'habitude, on va charger / décharger nos menus dans les fonctions loadGame() et cleanup(). 

   Notez aussi qu'on lance désormais le jeu avec le menu start grâce à la commande : setOnMenu(1, START); wink

 

Fichier : init.c : Remplacer les fonctions loadGame() et cleanup() par :

void loadGame(void)
{
 
//On charge les données pour la map
initMaps();
 
//On initialise les menus
initMenus();
 
//On charge la feuille de sprites du monstre
initMonsterSprites();
 
//On charge la feuille de sprites (spritesheet) de notre héros
initPlayerSprites();
 
//On commence au premier niveau
SetValeurDuNiveau(1);
changeLevel();
 
/* On initialise les variables du jeu */
setNombreDeVies(3);
setNombreDetoiles(0);
 
/* On charge le HUD */
initHUD();
 
//On charge notre plateforme
loadPlateforme();
 
//On charge la musique
loadSong("music/Caviator.mp3");
 
/* On charge les sounds Fx */
loadSound();
 
//On commence par le menu start
setOnMenu(1, START);
 
}
 
 
void cleanup()
{
//Nettoie les sprites de la map et des menus
cleanMaps();
cleanMenus();
 
/* Libère le sprite du héros */
cleanPlayer();
 
/* Libère le sprite des monstres */
cleanMonsters();
 
//Libère le HUD
cleanHUD();
 
//Libère la plateforme
cleanPlateforme();
 
/* Ferme la prise en charge du joystick */
closeJoystick();
 
/* On libère la musique */
cleanUpMusic();
 
//On libère les sons
freeSound();
 
//On quitte SDL_Mixer 2 et on décharge la mémoire
Mix_CloseAudio();
Mix_Quit();
 
//On fait le ménage et on remet les pointeurs à NULL
SDL_DestroyRenderer(renderer);
renderer = NULL;
SDL_DestroyWindow(screen);
screen = NULL;
 
//On quitte SDL_TTF 2
TTF_Quit();
 
//On quitte la SDL
SDL_Quit();
}

 

   Voilà, sauf que maintenant, quand on meurt, on aimerait bien retourner au menu Start ! cheeky
   Rien de plus simple ! wink Juste quelques lignes à rajouter tout en bas de notre fonction updatePlayer() !

   De même, l'appui sur la touche Enter (ou start) va maintenant ouvrir le menu de Pause ! angel
   Par souci de commodité, je vous ai remis toute la fonction updatePlayer() ci-dessous. Je vous laisse trouver les quelques lignes en plus (faut bien que je vous fasse travailler un peu quand même ! laugh) :

 

Fichier : player.c : Remplacer la fonction updatePlayer() par :

void updatePlayer(Input *input)
{
//On rajoute un timer au cas où notre héros mourrait lamentablement en tombant dans un trou...
//Si le timer vaut 0, c'est que tout va bien, sinon, on le décrémente jusqu'à 0, et là,
//on réinitialise.
//C'est pour ça qu'on ne gère le joueur que si ce timer vaut 0.
if (player.timerMort == 0)
{
//On gère le timer de l'invincibilité
if (player.invincibleTimer > 0)
player.invincibleTimer--;
 
//On réinitialise notre vecteur de déplacement latéral (X), pour éviter que le perso
//ne fonce de plus en plus vite pour atteindre la vitesse de la lumière ! ;)
//Essayez de le désactiver pour voir !
player.dirX = 0;
 
// La gravité fait toujours tomber le perso : on incrémente donc le vecteur Y
player.dirY += GRAVITY_SPEED;
 
//Mais on le limite pour ne pas que le joueur se mette à tomber trop vite quand même
if (player.dirY >= MAX_FALL_SPEED)
{
player.dirY = MAX_FALL_SPEED;
}
 
//Voilà, au lieu de changer directement les coordonnées du joueur, on passe par un vecteur
//qui sera utilisé par la fonction mapCollision(), qui regardera si on peut ou pas déplacer
//le joueur selon ce vecteur et changera les coordonnées du player en fonction.
if (input->left == 1)
{
player.dirX -= PLAYER_SPEED;
//Et on indique qu'il va à gauche (pour le flip
//de l'affichage, rappelez-vous).
player.direction = LEFT;
 
//Si ce n'était pas son état auparavant et qu'il est bien sur
//le sol (car l'anim' sera différente s'il est en l'air)
if (player.etat != WALK && player.onGround == 1)
{
//On enregistre l'anim' de la marche et on l'initialise à 0
player.etat = WALK;
player.frameNumber = 0;
player.frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
player.frameMax = 8;
}
}
 
//Si on détecte un appui sur la touche fléchée droite
else if (input->right == 1)
{
//On augmente les coordonnées en x du joueur
player.dirX += PLAYER_SPEED;
 
//Et on indique qu'il va à droite (pour le flip
//de l'affichage, rappelez-vous).
player.direction = RIGHT;
 
//Si ce n'était pas son état auparavant et qu'il est bien sur
//le sol (car l'anim' sera différente s'il est en l'air)
if (player.etat != WALK && player.onGround == 1)
{
//On enregistre l'anim' de la marche et on l'initialise à 0
player.etat = WALK;
player.frameNumber = 0;
player.frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
player.frameMax = 8;
}
}
 
//Si on n'appuie sur rien et qu'on est sur le sol, on charge l'animation marquant l'inactivité (Idle)
else if (input->right == 0 && input->left == 0 && player.onGround == 1)
{
//On teste si le joueur n'était pas déjà inactif, pour ne pas recharger l'animation
//à chaque tour de boucle
if (player.etat != IDLE)
{
//On enregistre l'anim' de l'inactivité et on l'initialise à 0
player.etat = IDLE;
player.frameNumber = 0;
player.frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
player.frameMax = 8;
}
 
}
 
 
//Et voici la fonction de saut très simple :
//Si on appuie sur la touche saut et qu'on est sur le sol, alors on attribue une valeur
//négative au vecteur Y
//parce que sauter veut dire se rapprocher du haut de l'écran et donc de y=0.
if (input->jump == 1)
{
if (player.onGround == 1)
{
player.dirY = -JUMP_HEIGHT;
player.onGround = 0;
player.jump = 1;
playSoundFx(JUMP);
}
 
/* Si on est en saut 1, on peut faire un deuxième bond et on remet jump1 à 0 */
else if (player.jump == 1)
{
player.dirY = -JUMP_HEIGHT;
player.jump = 0;
playSoundFx(JUMP);
}
 
input->jump = 0;
}
 
//Si on appuie sur Enter
if (input->enter == 1)
{
//On met le jeu en pause
setOnMenu(1, PAUSE);
input->enter = 0;
}
 
 
/* Réactive la possibilité de double saut si on tombe sans sauter */
if (player.onGround == 1)
player.jump = 1;
 
 
//On gère l'anim du saut
if (player.onGround == 0)
{
//Si on est en saut 1, on met l'anim' du saut normal
if (player.jump == 1)
{
if (player.etat != JUMP1)
{
player.etat = JUMP1;
player.frameNumber = 0;
player.frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
player.frameMax = 2;
}
}
else
{
if (player.etat != JUMP2)
{
player.etat = JUMP2;
player.frameNumber = 0;
player.frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
player.frameMax = 4;
}
}
}
 
//On rajoute notre fonction de détection des collisions qui va mettre à
//jour les coordonnées de notre super lapin.
mapCollision(&player);
 
//On gère le scrolling (fonction ci-dessous)
centerScrollingOnPlayer();
 
}
 
//Gestion de la mort quand le héros tombe dans un trou :
//Si timerMort est différent de 0, c'est qu'il faut réinitialiser le joueur.
//On ignore alors ce qui précède et on joue cette boucle (un wait en fait) jusqu'à ce que
// timerMort == 1. A ce moment-là, on le décrémente encore -> il vaut 0 et on réinitialise
//le jeu avec notre bonne vieille fonction d'initialisation ;) !
if (player.timerMort > 0)
{
player.timerMort--;
 
if (player.timerMort == 0)
{
// Si on est mort, on perd une vie
setNombreDeVies(getNombreDeVies() - 1);
 
//Sauf si on a plus de vies...
if (getNombreDeVies() < 0)
{
//Dans ce cas on retourne au menu start
setOnMenu(1, START);
}
 
//Sinon on réinitialise le niveau
changeLevel();
initializePlayer(0);
 
}
}
} 

 

    Plus qu'à mettre à jour notre catalogue de prototypes :

 

        Fichier : prototypes.h : Remplacez par :

#ifndef PROTOTYPES
#define PROTOTYPES
 
#include "structs.h"
 
/* Catalogue des prototypes des fonctions utilisées.
On le complétera au fur et à mesure. */
 
extern void centerScrollingOnPlayer(void);
extern void changeLevel(void);
extern void checkCollisionsWithPlateforms(GameObject *entity);
extern int checkFall(GameObject monster);
extern void cleanHUD(void);
extern void cleanMaps(void);
extern void cleanMenus(void);
extern void cleanMonsters(void);
extern void cleanPlateforme(void);
extern void cleanPlayer(void);
extern void cleanup(void);
extern void cleanUpMusic(void);
extern void closeFont(void);
extern void closeJoystick(void);
extern int collide(GameObject *player, GameObject *monster);
extern void delay(unsigned int frameLimit);
extern void doPlateforme(void);
extern void drawGame(int pauseMenu);
extern void drawHud(void);
extern void drawImage(SDL_Texture *, int, int);
extern void drawMap(int);
extern void drawMonster(GameObject *entity);
extern void drawPauseMenu(void);
extern void drawPlateforme(void);
extern void drawPlayer(void);
extern void drawStartMenu(void);
extern void drawString(char *text, int x, int y, int r, int g, int b, int a);
extern void drawTile(SDL_Texture *image, int destx, int desty, int srcx, int srcy);
extern void freeSound(void);
extern void gestionInputs(Input *input);
extern SDL_Texture *getBackground(void);
extern int getBeginX(void);
extern int getBeginY(void);
extern void getInput(Input *input);
extern void getItem(int itemNumber);
extern void getJoystick(Input *input);
extern int getLevel(void);
extern int getLife(void);
extern int getMaxX(void);
extern int getMaxY(void);
extern int getMenuType(void);
extern GameObject *getMonster(int nombre);
extern int getMonsterNumber(void);
extern int getNombreDetoiles(void);
extern int getNombreDeVies(void);
extern int getOnMenu(void);
extern int getPlateformeNumber(void);
extern GameObject *getPlayer(void);
extern int getPlayerDirection(void);
extern int getPlayerx(void);
extern int getPlayery(void);
extern SDL_Renderer *getrenderer(void);
extern int getStartX(void);
extern int getStartY(void);
extern SDL_Texture *getTileSetA(void);
extern SDL_Texture *getTileSetB(void);
extern int getTileValue(int y, int x);
extern void init(char *);
extern void initHUD(void);
extern void initMaps(void);
extern void initMenus(void);
extern void initializeNewMonster(int x, int y);
extern void initMonsterSprites(void);
extern void initPlateforme(int x, int y, int type);
extern void initPlayerSprites(void);
extern void initializePlayer(int newLevel);
extern void killPlayer(void);
extern void loadFont(char *, int);
extern void loadGame(void);
extern SDL_Texture *loadImage(char *name);
extern void loadMap(char *name);
extern void loadPlateforme(void);
extern void loadSong(char filename[200]);
extern void loadSound(void);
extern void mapCollision(GameObject *entity);
extern void monsterCollisionToMap(GameObject *entity);
extern void openJoystick(void);
extern void playerHurts(GameObject *monster);
extern void playSoundFx(int type);
extern void resetCheckpoint(void);
extern void resetMonsters(void);
extern void resetPlateformes(void);
extern void setNombreDeVies(int valeur);
extern void setNombreDetoiles(int valeur);
extern void setOnMenu(int valeur, int type);
extern void setPlayerx(int valeur);
extern void setPlayery(int valeur);
extern void setStartX(int valeur);
extern void setStartY(int valeur);
extern void SetValeurDuNiveau(int valeur);
extern void updateMonsters();
extern void updatePauseMenu(Input *input);
extern void updatePlayer(Input *input);
extern void updateStartMenu(Input *input);
 
#endif

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

   Et maintenant, on commence le jeu par un joli menu ! Ô joie ! angel

   Je vous laisse donc tester tout ça et je vous retrouve au chapitre suivant !

   

 

   @ bientôt pour le chapitre 19 ! 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!