Big Tuto SDL 2 : Rabidja v. 3.0

Chapitre 16 : Vole, plateforme, vole !

 

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

Dernière mise à jour : 11 novembre 2015

 

      Prologue

   Comme vous n'aurez pas manqué de le remarquer, on se retrouve pour l'instant dans notre jeu avec des tiles de plateformes flottantes, mais elles ne fonctionnent pas ! surprise Impossible donc de terminer le premier niveau officiel, par exemple... frown

   Mais on va remédier à ce problème dès maintenant ! angel

   Pour rappel, les tiles dont je vous parle sont ces tiles représentant une plateforme rouge avec une flèche en-dessous. Il y en a de deux types : celles qui vont de gauche à droite et celles qui vont de haut en bas. wink

   Et voilà, comment on va les faire fonctionner : quand le jeu va rencontrer une de ces tiles à afficher, il ne va pas l'afficher, mais il va l'effacer et initialiser une plateforme à sa place. Cela correspond exactement à ce qu'on a déjà fait pour créer nos monstres. wink

   Ensuite, suivant le numéro de la tile (et donc suivant la flèche sur le petit dessin de la tile), on déplacera notre plateforme soit de gauche à droite, soit de haut en bas.

   Bien entendu, il va aussi falloir qu'on teste les collisions avec notre lapin-sauteur, si on ne veut pas qu'il passe au-travers ! indecision

   Allez, on est parti ! Les vacances sont finies, car ce tuto s'annonce ancore une fois assez long ! cheeky

 

      Nouveaux fichiers à ajouter au projet

   Avant de commencer, il va nous falloir ajouter un nouveau fichier image pour notre plateforme. Le voilà :


plateforme.png

   Enregistrez-le simplement dans le dossier graphics de votre projet, sous le nom : plateforme.png.
   Passons maintenant au code ! angel

      Le code

   On va commencer par retourner dans notre fichier defs.h pour créer quelques nouvelles defines, qui vont nous aider à gérer nos plateformes : leur nombre max d'abord (50 devrait faire l'affaire cheeky), leur vitesse, ainsi que les directions Haut et Bas qu'elles peuvent prendre (notez que vous pouvez en créer qui vont aussi en diagonale, si le coeur vous en dit wink ).   

Fichier : defs.h : Rajouter :

/* Gestion des plateformes mobiles */
#define PLATEFORMES_MAX 50
#define PLATEFORM_SPEED 2
#define UP 3
#define DOWN 4 
 
    On va ensuite modifier notre structure GameObject dans le fichier structs.h pour rajouter les variables dont on va avoir besoin pour nos plateformes :
- beginX, beginY : seront les coordonnées de départ de notre plateforme (son point de spawn correspondant au coin haut gauche de notre tile wink),
- type : va nous indiquer s'il s'agit de la plateforme de type 1 (qui va de gauche à droite) ou de type 2 (qui va de haut en bas);
- player_dessus : on l'utilisera comme un booléen, pour savoir si le joueur se trouve sur la plateforme ou non.
  Ajoutons donc tout cela :

 

Fichier : structs.h : Rajouter à la struct GameObject :

//Variables pour gérer les plateformes flottantes
//Coordonnées de départ
int beginX, beginY;
 
// Type de plateforme (horizontale ou verticale)
// Le joueur est-il dessus ?
int type, player_dessus; 

 

   On va ensuite créer un nouveau fichier plateformes.c et y copier nos nouvelles fonctions, que je vous expliquerai ci-dessous :

 

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

#include "prototypes.h"
 
 
GameObject plateforme[50];
SDL_Texture *plateformeTexture;
int nombrePlateformes;
 
 
void loadPlateforme(void)
{
//On charge l'image de la plateforme
plateformeTexture = loadImage("graphics/plateforme.png");
 
/* Si on ne peut pas, on quitte, et on l'indique en erreur ;) */
if (plateformeTexture == NULL)
{
printf("Impossible de charger l'image de la plateforme : graphics/plateforme.png/n");
exit(1);
}
}
 
 
void cleanPlateforme(void)
{
if (plateformeTexture != NULL)
{
SDL_DestroyTexture(plateformeTexture);
}
}
 
 
int getPlateformeNumber(void)
{
return nombrePlateformes;
}
 
 
void resetPlateformes(void)
{
nombrePlateformes = 0;
}
 
 
void initPlateforme(int x, int y, int type)
{
 
/* On rajoute une plateforme à la liste des plateformes */
nombrePlateformes++;
 
//S'il y en a trop, on fait une erreur et on quitte
if (nombrePlateformes > PLATEFORMES_MAX)
{
printf("Trop de plateformes initialisees !\nEnlevez-en ou changez leur nombre max.\n");
exit(1);
}
 
//On remplit notre structure
plateforme[nombrePlateformes].x = plateforme[nombrePlateformes].beginX = x;
plateforme[nombrePlateformes].y = plateforme[nombrePlateformes].beginY = y;
 
//On enregistre la taille de l'image
SDL_QueryTexture(plateformeTexture, NULL, NULL, &plateforme[nombrePlateformes].w, &plateforme[nombrePlateformes].h);
 
plateforme[nombrePlateformes].type = type;
 
//Si elle est du type 2, elle monte, sinon elle va à droite
if (plateforme[nombrePlateformes].type == 2)
plateforme[nombrePlateformes].direction = UP;
else
plateforme[nombrePlateformes].direction = RIGHT;
 
}
 
 
void doPlateforme(void)
{
 
int i;
 
for (i = 1; i <= nombrePlateformes; i++)
{
/* Déplacement UP/DOWN (haut/bas) */
if (plateforme[i].type == 2)
{
if (plateforme[i].direction == UP)
{
plateforme[i].y -= PLATEFORM_SPEED;
 
/* Si le joueur est dessus, on le déplace avec
pour éviter qu'il ne reste immobile et que la
plateforme se barre comme sur certains vieux
(mauvais) jeux...*/
if (plateforme[i].player_dessus == 1)
setPlayery(getPlayery() - PLATEFORM_SPEED);
}
else
{
plateforme[i].y += PLATEFORM_SPEED;
 
/* Si le joueur est dessus, on le déplace avec */
if (plateforme[i].player_dessus == 1)
setPlayery(getPlayery() + PLATEFORM_SPEED);
}
 
//Test : si la plateforme dépasse 5 tiles de largeur,
//on lui fait faire demi-tour pour ne pas qu'elle
//sorte de la map ! :D
if (plateforme[i].y > plateforme[i].beginY + 5 * TILE_SIZE)
plateforme[i].direction = UP;
 
 
if (plateforme[i].y < plateforme[i].beginY)
plateforme[i].direction = DOWN;
}
 
/* Déplacement RIGHT/LEFT */
else
{
if (plateforme[i].direction == RIGHT)
{
plateforme[i].x += PLATEFORM_SPEED;
 
/* Si le joueur est dessus, on le déplace avec */
if (plateforme[i].player_dessus == 1)
setPlayerx(getPlayerx() + PLATEFORM_SPEED);
}
else
{
plateforme[i].x -= PLATEFORM_SPEED;
 
/* Si le joueur est dessus, on le déplace avec */
if (plateforme[i].player_dessus == 1)
setPlayerx(getPlayerx() - PLATEFORM_SPEED);
}
 
//Test : si la plateforme dépasse 5 tiles de longueur,
//on lui fait faire demi-tour pour ne pas qu'elle
//fasse toute la map ! :D
if (plateforme[i].x > plateforme[i].beginX + 5 * TILE_SIZE)
plateforme[i].direction = LEFT;
 
if (plateforme[i].x < plateforme[i].beginX)
plateforme[i].direction = RIGHT;
}
 
}
 
}
 
 
void drawPlateforme(void)
{
 
int i;
 
for (i = 1; i <= nombrePlateformes; i++)
{
drawImage(plateformeTexture, plateforme[i].x - getStartX(), plateforme[i].y - getStartY());
}
 
}
 
 
 
void checkCollisionsWithPlateforms(GameObject *entity)
{
int j;
 
for (j = 1; j <= nombrePlateformes; j++)
{
if (entity->x + entity->w >= plateforme[j].x
&& entity->x <= plateforme[j].x + plateforme[j].w
&& entity->y + entity->h >= plateforme[j].y
&& entity->y + entity->h < plateforme[j].y + 32)
{
// Place the player as close to the plateform as possible
entity->y = plateforme[j].y - entity->h;
entity->dirY = 0;
entity->onGround = 1;
 
plateforme[j].player_dessus = 1;
}
 
else
plateforme[j].player_dessus = 0;
}
 
}

 

    Pour créer nos plateformes, on va faire comme pour les monstres et initialiser un nouveau tableau de GameObjects.
    Pour ne pas être limité au niveau du level design, on va carrément créer un tableau de 50 cases (chiffre correspondant à notre def wink), comme ça, on pourra créer jusqu'à 50 plateformes par niveau ! Mais, bien sûr, vous pouvez moduler selon vos besoins.

   Nous rajoutons ensuite un compteur (comme pour les monstres) que nous nommerons nombrePlateformes, et un SDL_Surface qui contiendra le sprite de notre plateforme.

 

   Voilà, passons maintenant au survol de nos nouvelles fonctions cool :

- les 4 premières fonctions sont classiques et ne devraient pas vous surprendre : on charge / décharge notre sprite, et on crée 2 fonctions get / reset pour pouvoir retouver le nombre de plateformes en jeu et les réinitialiser quand on recharge le niveau. wink
- initPlateforme(int x, int y, int type) est appelée depuis la fonction drawMap() et initialise une nouvelle plateforme aux coordonnées passées, et avec le bon type (gauche/droite ou bas/haut). Cela correspond à peu près à ce que l'on fait déjà pour les monstres, si vous vous rappelez bien. cheeky
- doPlateforme() s'occupe de déplacer nos plateformes à la vitesse indiquée et dans le bons sens (tout en gérant le demi-tour au bout 5 tiles),
- drawPlateforme() affiche simplement nos plateformes.

- et checkCollisionsWithPlateforms() se charge de vérifier si le joueur entre ou pas en collision avec une plateforme. Si c'est le cas, on le place sur la plateforme de la même façon, qu'on le plaçait sur une tile sol, et on passe la variable player_dessus à 1. Cette variable nous sert dans la fonction précédente doPlateforme() pour déplacer le joueur en même temps que la plateforme, sinon elle filerait sans lui ! surprise

    Voilà, sinon tout est expliqué dans le code. wink

 

   Passons maintenant au fichier map.c, où nous allons rajouter un appel à checkCollisionsWithPlateforms(), dans la partie du code gérant les déplacements vers le bas de notre héros :

   if (getPlateformeNumber > 0)
checkCollisionsWithPlateforms(entity);
 

   Ainsi, il ne passera pas au-travers des plateformes ! wink

   Je vous ai remis le détail du code ci-dessous pour que vous vous y retrouviez (le code ci-dessus est à copier tout à la fin de ce passage cheeky) :

 

Fichier : map.c : Modifier la fonction (déplacement en bas -
rajouter le test de collision avec la plateforme mobile)
 :

/* Déplacement en bas */
 
//Test des tiles Power-up)
if (map.tile[y2][x1] >= TILE_POWER_UP_DEBUT
&& map.tile[y2][x1] <= TILE_POWER_UP_FIN)
{
//On appelle la fonction getItem()
getItem(map.tile[y2][x1] - TILE_POWER_UP_DEBUT + 1);
 
//On remplace la tile power-up par une tile transparente
map.tile[y2][x1] = 0;
}
else if (map.tile[y2][x2] >= TILE_POWER_UP_DEBUT
&& map.tile[y2][x2] <= TILE_POWER_UP_FIN)
{
//On appelle la fonction getItem()
getItem(map.tile[y2][x2] - TILE_POWER_UP_DEBUT + 1);
 
//On remplace la tile power-up par une tile transparente
map.tile[y2][x2] = 0;
}
 
 
/* Gestion des pics */
if ((map.tile[y2][x1] == TILE_PIKES) || (map.tile[y2][x2] == TILE_PIKES))
{
 
//On joue le son
playSoundFx(DESTROY);
//On fait sauter le joueur
entity->dirY = -JUMP_HEIGHT;
 
if (entity->life > 1)
{
//Si le timer d'invincibilité est à 0
//on perd un coeur
if (entity->invincibleTimer == 0)
{
entity->life--;
entity->invincibleTimer = 80;
}
}
else
{
//On met le timer à 1 pour tuer le joueur intantanément
entity->timerMort = 1;
//On joue le son
playSoundFx(DESTROY);
}
}
 
/* Gestion du ressort */
else if ((map.tile[y2][x1] == TILE_RESSORT) || (map.tile[y2][x2] == TILE_RESSORT))
{
entity->dirY = -20;
//On indique au jeu qu'il a atterri pour réinitialiser le double saut
entity->onGround = 1;
playSoundFx(BUMPER);
}
 
 
//Gestion des plateformes traversables : elles se situent juste avant
//les tiles bloquantes dans notre tileset (dont la valeur butoire est
//BLANK_TILE). Il suffit donc d'utiliser le numéro de la première tile
//traversable au lieu de BLANK_TILE pour bloquer le joueur,
//seulement quand il tombe dessus (sinon, il passe au-travers
//et le test n'est donc pas effectué dans les autres directions
else if (map.tile[y2][x1] > TILE_TRAVERSABLE || map.tile[y2][x2] > TILE_TRAVERSABLE)
{
//Si la tile est une plateforme ou une tile solide, on y colle le joueur et
//on le déclare sur le sol (onGround).
entity->y = y2 * TILE_SIZE;
entity->y -= entity->h;
entity->dirY = 0;
entity->onGround = 1;
}
 
 
// Test de collision avec la plateforme mobile
if (getPlateformeNumber > 0)
checkCollisionsWithPlateforms(entity);
 
}

 

  Voilà, maintenant, que c'est fait, allons dans la fonction drawMap() et initialisons nos premières plateformes !  Pour cela, on rajoute simplement un système de détection comme pour les monstres et on initialise une plateforme. wink

 

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

void drawMap(int layer)
{
int x, y, mapX, x1, x2, mapY, y1, y2, xsource, ysource, a;
 
/* On initialise mapX à la 1ère colonne qu'on doit blitter.
Celle-ci correspond au x de la map (en pixels) divisés par la taille d'une tile (32)
pour obtenir la bonne colonne de notre map
Exemple : si x du début de la map = 1026, on fait 1026 / 32
et on sait qu'on doit commencer par afficher la 32eme colonne de tiles de notre map */
mapX = map.startX / TILE_SIZE;
 
/* Coordonnées de départ pour l'affichage de la map : permet
de déterminer à quels coordonnées blitter la 1ère colonne de tiles au pixel près
(par exemple, si la 1ère colonne n'est visible qu'en partie, on devra commencer à blitter
hors écran, donc avoir des coordonnées négatives - d'où le -1). */
x1 = (map.startX % TILE_SIZE) * -1;
 
/* Calcul des coordonnées de la fin de la map : jusqu'où doit-on blitter ?
Logiquement, on doit aller à x1 (départ) + SCREEN_WIDTH (la largeur de l'écran).
Mais si on a commencé à blitter en dehors de l'écran la première colonne, il
va falloir rajouter une autre colonne de tiles sinon on va avoir des pixels
blancs. C'est ce que fait : x1 == 0 ? 0 : TILE_SIZE qu'on pourrait traduire par:
if(x1 != 0)
x2 = x1 + SCREEN_WIDTH + TILE_SIZE , mais forcément, c'est plus long ;)*/
x2 = x1 + SCREEN_WIDTH + (x1 == 0 ? 0 : TILE_SIZE);
 
/* On fait exactement pareil pour calculer y */
mapY = map.startY / TILE_SIZE;
y1 = (map.startY % TILE_SIZE) * -1;
y2 = y1 + SCREEN_HEIGHT + (y1 == 0 ? 0 : TILE_SIZE);
 
 
//On met en place un timer pour animer la map 
if (map.mapTimer <= 0)
{
if (map.tileSetNumber == 0)
{
map.tileSetNumber = 1;
map.mapTimer = TIME_BETWEEN_2_FRAMES * 3;
}
else
{
map.tileSetNumber = 0;
map.mapTimer = TIME_BETWEEN_2_FRAMES * 3;
}
}
else
map.mapTimer--;
 
 
/* Dessine la carte en commençant par startX et startY */
 
/* On dessine ligne par ligne en commençant par y1 (0) jusqu'à y2 (480)
A chaque fois, on rajoute TILE_SIZE (donc 32), car on descend d'une ligne
de tile (qui fait 32 pixels de hauteur) */
if (layer == 1)
{
for (y = y1; y < y2; y += TILE_SIZE)
{
/* A chaque début de ligne, on réinitialise mapX qui contient la colonne
(0 au début puisqu'on ne scrolle pas) */
mapX = map.startX / TILE_SIZE;
 
/* A chaque colonne de tile, on dessine la bonne tile en allant
de x = 0 à x = 640 */
for (x = x1; x < x2; x += TILE_SIZE)
{
 
//Si la tile à dessiner n'est pas une tile vide
if (map.tile[mapY][mapX] != 0)
{
/*On teste si c'est une tile monstre */
if (map.tile[mapY][mapX] == TILE_MONSTRE)
{
//On initialise un monstre en envoyant les coordonnées de la tile
initializeNewMonster(mapX * TILE_SIZE, mapY * TILE_SIZE);
//Et on efface cette tile de notre tableau pour éviter un spawn de monstres
//infini !
map.tile[mapY][mapX] = 0;
}
 
/*On teste si c'est une tile plateforme flottante */
else if (map.tile[mapY][mapX] >= TILE_PLATEFORME_DEBUT
&& map.tile[mapY][mapX] <= TILE_PLATEFORME_FIN)
{
//On initialise une plateforme flottante
//Pour obtenir le type (dernier arg), on enlève le numéro de la 1ère tile plateforme
//(TILE_PLATEFORME_DEBUT) au numéro de la til en cours (map.tile[mapY][mapX])
//et on rajoute 1 pour que le premier type soit le 1 et pas le 0 ;)
initPlateforme(mapX * TILE_SIZE, mapY * TILE_SIZE, map.tile[mapY][mapX] - TILE_PLATEFORME_DEBUT + 1);
 
//Et on efface cette tile de notre tableau pour éviter un spawn de plateformes
//infini !
map.tile[mapY][mapX] = 0;
}
}
 
/* Suivant le numéro de notre tile, on découpe le tileset (a = le numéro
de la tile */
a = map.tile[mapY][mapX];
 
/* Calcul pour obtenir son y (pour un tileset de 10 tiles
par ligne, d'où le 10 */
ysource = a / 10 * TILE_SIZE;
/* Et son x */
xsource = a % 10 * TILE_SIZE;
 
/* Fonction qui blitte la bonne tile au bon endroit suivant le timer */
if (map.tileSetNumber == 0)
drawTile(map.tileSet, x, y, xsource, ysource);
else
drawTile(map.tileSetB, x, y, xsource, ysource);
 
mapX++;
}
 
mapY++;
}
}
 
else if (layer == 2)
{
//Deuxième couche de tiles ;)
for (y = y1; y < y2; y += TILE_SIZE)
{
mapX = map.startX / TILE_SIZE;
 
for (x = x1; x < x2; x += TILE_SIZE)
{
//Si la tile à dessiner n'est pas une tile vide
if (map.tile2[mapY][mapX] != 0)
{
/*On teste si c'est une tile monstre */
if (map.tile2[mapY][mapX] == TILE_MONSTRE)
{
//On initialise un monstre en envoyant les coordonnées de la tile
initializeNewMonster(mapX * TILE_SIZE, mapY * TILE_SIZE);
//Et on efface cette tile de notre tableau pour éviter un spawn de monstres
//infini !
map.tile2[mapY][mapX] = 0;
}
 
/*On teste si c'est une tile plateforme flottante */
else if (map.tile2[mapY][mapX] >= TILE_PLATEFORME_DEBUT
&& map.tile2[mapY][mapX] <= TILE_PLATEFORME_FIN)
{
//On initialise une plateforme flottante
//Pour obtenir le type (dernier arg), on enlève le numéro de la 1ère tile plateforme
//(TILE_PLATEFORME_DEBUT) au numéro de la til en cours (map.tile[mapY][mapX])
//et on rajoute 1 pour que le premier type soit le 1 et pas le 0 ;)
initPlateforme(mapX * TILE_SIZE, mapY * TILE_SIZE, map.tile2[mapY][mapX] - TILE_PLATEFORME_DEBUT + 1);
//Et on efface cette tile de notre tableau pour éviter un spawn de plateformes
//infini !
map.tile2[mapY][mapX] = 0;
}
}
 
/* Suivant le numéro de notre tile, on découpe le tileset (a = le numéro
de la tile */
a = map.tile2[mapY][mapX];
 
/* Calcul pour obtenir son y (pour un tileset de 10 tiles
par ligne, d'où le 10 */
ysource = a / 10 * TILE_SIZE;
/* Et son x */
xsource = a % 10 * TILE_SIZE;
 
/* Fonction qui blitte la bonne tile au bon endroit suivant le timer */
if (map.tileSetNumber == 0)
drawTile(map.tileSet, x, y, xsource, ysource);
else
drawTile(map.tileSetB, x, y, xsource, ysource);
 
mapX++;
}
mapY++;
}
}
 
else if (layer == 3)
{
//Troisième couche de tiles ;)
for (y = y1; y < y2; y += TILE_SIZE)
{
mapX = map.startX / TILE_SIZE;
 
for (x = x1; x < x2; x += TILE_SIZE)
{
//Si la tile à dessiner n'est pas une tile vide
if (map.tile3[mapY][mapX] != 0)
{
/*On teste si c'est une tile monstre */
if (map.tile3[mapY][mapX] == TILE_MONSTRE)
{
//On initialise un monstre en envoyant les coordonnées de la tile
initializeNewMonster(mapX * TILE_SIZE, mapY * TILE_SIZE);
//Et on efface cette tile de notre tableau pour éviter un spawn de monstres
//infini !
map.tile3[mapY][mapX] = 0;
}
 
/*On teste si c'est une tile plateforme flottante */
else if (map.tile3[mapY][mapX] >= TILE_PLATEFORME_DEBUT
&& map.tile3[mapY][mapX] <= TILE_PLATEFORME_FIN)
{
//On initialise une plateforme flottante
//Pour obtenir le type (dernier arg), on enlève le numéro de la 1ère tile plateforme
//(TILE_PLATEFORME_DEBUT) au numéro de la til en cours (map.tile[mapY][mapX])
//et on rajoute 1 pour que le premier type soit le 1 et pas le 0 ;)
initPlateforme(mapX * TILE_SIZE, mapY * TILE_SIZE, map.tile3[mapY][mapX] - TILE_PLATEFORME_DEBUT + 1);
//Et on efface cette tile de notre tableau pour éviter un spawn de plateformes
//infini !
map.tile3[mapY][mapX] = 0;
}
}
 
/* Suivant le numéro de notre tile, on découpe le tileset (a = le numéro
de la tile */
a = map.tile3[mapY][mapX];
 
/* Calcul pour obtenir son y (pour un tileset de 10 tiles
par ligne, d'où le 10 */
ysource = a / 10 * TILE_SIZE;
/* Et son x */
xsource = a % 10 * TILE_SIZE;
 
/* Fonction qui blitte la bonne tile au bon endroit suivant le timer */
if (map.tileSetNumber == 0)
drawTile(map.tileSet, x, y, xsource, ysource);
else
drawTile(map.tileSetB, x, y, xsource, ysource);
 
mapX++;
}
mapY++;
}
}
 
 
} 

  

   Le code est long, mais là encore, redondant pour chaque couche. Sinon, il n'y a pas de difficulté particulière wink.

   Maintenant que nos plateformes existent et sont prêtes à être gérées, il nous faut encore les initialiser, sinon elles n'apparaîtront jamais !
   Commençons donc par charger notre sprite de plateforme, que vous avez bien copié sous le dossier /graphics. On va appeler notre fonction loadPlateforme() depuis la fonction loadGame() :  Sans oublier, une fois encore, le cleanup(), à la fin :

 

Fichier : init.c : Remplacer les fonctions suivantes :

void loadGame(void)
{
 
//On charge les données pour la map
initMaps();
 
//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();
 
}
 
 
void cleanup()
{
//Nettoie les sprites de la map
cleanMaps();
 
/* 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();
} 

 

   On met ensuite à jour le main() en rajoutant un appel à doPlateforme() :

 

Fichier : main.c : Modifier le main() en rajoutant doPlateforme() :

// Boucle infinie, principale, du jeu
while (go == 1)
{
//Gestion des inputs clavier
gestionInputs(&input);
 
// On met à jour le jeu, en commençant par le joueur
updatePlayer(&input);
 
//On update les monstres
updateMonsters();
 
//On update les plateformes mobiles
doPlateforme();

 

 

   Voilà, il nous manque encore la fonction draw(), qu'on doit aussi mettre à jour en appelant drawPlateforme() :

 

Fichier : draw.c : Modifier drawGame() en rajoutant drawPlateforme() :

void drawGame(void)
{
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();

 

  

   On a terminé ? indecision
   Presque, mais pas tout à fait cheeky : il faut encore qu'on remette le compteur de plateformes à zéro quand on meurt, sinon on risque de se retrouver avec des plateformes partout !!! angry

   Pour cela, c'est très simple, il suffit d'aller dans la fonction initializePlayer() et d'appeler resetPlateformes()angel

 

Fichier : player.c : Modifier initializePlayer() en rajoutant resetPlateformes()  :

void initializePlayer(int newLevel)
{
 
//PV à 3
player.life = 3;
 
//Timer d'invincibilité à 0
player.invincibleTimer = 0;
 
//Nombre de plateformes flottantes à 0
resetPlateformes();
 

   

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

 

        Fichier : prototypes.h : Remplacez par :

//Rabidja 3 - nouvelle version intégralement en SDL 2.0
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
 
#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 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(void);
extern void drawHud(void);
extern void drawImage(SDL_Texture *, int, int);
extern void drawMap(int);
extern void drawMonster(GameObject *entity);
extern void drawPlateforme(void);
extern void drawPlayer(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 GameObject *getMonster(int nombre);
extern int getMonsterNumber(void);
extern int getNombreDetoiles(void);
extern int getNombreDeVies(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 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 resetMonsters(void);
extern void resetPlateformes(void);
extern void setNombreDeVies(int valeur);
extern void setNombreDetoiles(int valeur);
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 updatePlayer(Input *input);
 
#endif

 

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

   Maintenant, baladez-vous et vous verrez que les tiles plateformes sont maintenant remplacées par de jolies plateformes qui bougent ! surprise

   Si c'est pas chouette, ça ! angel Sautez dessus, et oh magie ! Notre lapin tient dessus et se déplace avec elles ! cheeky

   Vous allez enfin pouvoir parcourir le 1er niveau officiel du jeu en entier ! wink Et quand vous en aurez marre, il sera temps de passer au niveau 2, dans le prochain chapitre ! cool

   

 

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