Big Tuto SDL 2 : Rabidja v. 3.0

Chapitre 10 : Collisions avec la map

 

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

Dernière mise à jour : 9 novembre 2015

 

      Prologue

   On a maintenant un héros flottant dans les airs ! cheeky

   C'est cool, mais c'est pas superman, non plus !... indecision Nous, c'est super lapin ninja, alias Rabidja ! Et comme tout bon lapin, il doit bondir partout ! angel

   Mais pour bondir, il faut aussi qu'on gère les collisions avec la map ! wink

   Alors, qu'est-ce qu'on attend !?! Au boulot ! laugh

 

      Le code

   Nous allons d'abord commencer par rajouter quelques nouvelles defs dont nous allons avoir besoin par la suite pour gérer nos tiles (cf. chapitre 7).

   Ouvrez donc le fichier defs.h et rajoutez les valeurs suivantes :

Fichier : defs.h : Rajoutez :

/* VALEURS DES TILES (cf. chapitre 7) */
 
// Constante définissant le seuil entre les tiles traversables
// (blank) et les tiles solides
#define BLANK_TILE 89
 
//Plateformes traversables
#define TILE_TRAVERSABLE 70
 
//Tiles Power-ups
#define TILE_POWER_UP_DEBUT 67
#define TILE_POWER_UP_FIN 69
#define TILE_POWER_UP_COEUR 68
 
//Autres Tiles spéciales
#define TILE_RESSORT 115
#define TILE_CHECKPOINT 23
#define TILE_MONSTRE 126
#define TILE_PIKES 117
 
//Tiles plateformes mobiles
#define TILE_PLATEFORME_DEBUT 120
#define TILE_PLATEFORME_FIN 121

   Ces valeurs correspondent tout simplement au numéro de la ou les tile(s) correspondantes. Ainsi, nos tiles sont traversables jusqu'à la tile 89, sauf les tiles 70 à 89 qui sont des plateformes (et donc elles ne seront pas traversables par le haut wink ). Les autres tiles seront toutes solides (le joueur se cognera dedans cheeky).

   Sauf les tiles spéciales : 
- pour les tiles power-ups (étoiles, coeurs, vies), on les fera disparaître quand le joueur les touchera et on lui attribuera le power-up correspondant.
- pour la tile ressort, elle fera rebondir le joueur quand il tombera dessus (sinon, elle sera solide sur les autres côtés),
- au contraire, la tile pics blessera le joueur,
- pour la tile checkpoint, elle changera quand le joueur la touchera (on aura un petit drapeau qui se lèvera) et on enregistrera le checkpoint,
- pour la tile monstre, on la remplacera par un sprite de monstres à l'affichage,
- idem pour les tiles de plateformes mobiles.

   Bien entendu, ces tiles spéciales ne seront pas actives dès ce chapitre et s'afficheront donc telles quelles (on pourra parfois se cogner dedans, comme pour les tiles monstres). On reverra leur fonctionnement plus en détails dans des chapitres ultérieurs qui leur seront dédiés. cool

   Retournons maintenant dans notre fichier player.c et complétons notre fonction updatePlayer() :

Fichier : player.c : Remplacez la fonction précédente 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;
}
/* 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;
}
input->jump = 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 réinitialise le niveau
changeLevel();
initializePlayer(0);
}
}
}

   Le plus simple pour vous sera sans doute de remplacer votre fonction existante, après avoir regardé les morceaux de code qui changent. wink

   Et qu'est-ce qui change justement ? cheeky

   J'ai largement commenté la fonction pour vous aider à vous y repérer, mais globalement, on ajoute d'abord notre timerMort qui permettra de savoir si notre héros est vivant ou non. Ainsi, si on le met à 1, on déclare notre héros mort (ça marchera avec les monstres aussi par la suite wink) et il nous sert alors aussi à faire une boucle de temporisation, avant de le ressusciter (sinon, ça aurait été un peu déstabilisant de le faire revivre dans la seconde, avant même que le joueur ait pigé pourquoi il était mort ! laugh).

   Ensuite, on rajoute notre saut et notre double saut : le système fonctionne ainsi : on applique un vecteur pesanteur à notre héros (GRAVITY_SPEED sur dirY) qui le fait tomber jusqu'à sa vitesse max (MAX_FALL_SPEED). Ensuite, dans notre fonction mapCollision() que nous étudierons ensuite et qui gèrera les collisions avec la map, on testera si notre héros est sur (ou dans) une tile solide, et on le calera à ce moment-là contre elle (parce que coincé dedans, ça serait pas top... cheeky). Notre héros sera alors onGround (sur le sol).

   Dès lors, si on appuie sur la touche SAUT, on enlève -JUMP_HEIGHT à son dirY pour le faire monter vers le haut de l'écran, et donc sauter, et on change la valeur de son anim'. Même chose, la fonction mapCollision() vérifiera que le perso ne rentre pas dans le plafond en haut et le stoppera avant ! laugh

   Pour le double saut, on ne peut plus utiliser notre fonction onGround, on va donc utiliser une nouvelle variable jump, de la même façon. Sans elle, on pourrait double sauter à volonté (vous pouvez tester wink).

   Voilà globalement ce qui a changé. Je vous laisse suivre les commentaires pour le reste. wink Reprenons maintenant notre fonction centerScrollingOnPlayer() :

Fichier : player.c : Remplacez la fonction précédente par :

void centerScrollingOnPlayer(void)
{
// Nouveau scrolling à sous-boîte limite :
//Pour éviter les effets de saccades dus à une caméra qui se
//centre automatiquement et constamment sur le joueur (ce qui
//peut en rendre malade certains...), on crée une "boîte" imaginaire
//autour du joueur. Quand on dépasse un de ses bords (en haut, en bas,
//à gauche ou à droite), on scrolle.
//Mais là encore, au lieu de centrer sur le joueur, on déplace simplement
//la caméra jusqu'à arriver au joueur. On a changé ici la valeur à 4 pixels
//pour que le jeu soit plus rapide.
int cxperso = player.x + player.w / 2;
int cyperso = player.y + player.h / 2;
int xlimmin = getStartX() + LIMITE_X;
int xlimmax = xlimmin + LIMITE_W;
int ylimmin = getStartY() + LIMITE_Y;
int ylimmax = ylimmin + LIMITE_H;
 
//Effet de retour en arrière quand on est mort :
//Si on est très loin de la caméra, plus loin que le bord
//de la map, on accélère le scrolling :
if (cxperso < getStartX())
{
setStartX(getStartX() - 30);
}
 
//Si on dépasse par la gauche, on recule la caméra
else if (cxperso < xlimmin)
{
setStartX(getStartX() - 4);
}
 
//Effet de retour en avant quand on est mort (au
//cas où le joueur s'amuse à faire le niveau à rebours
//après une checkpoint) :
//Si on est très loin de la caméra, plus loin que le bord
//de la map, on accélère le scrolling :
if (cxperso > getStartX() + SCREEN_WIDTH)
{
setStartX(getStartX() + 30);
}
 
//Si on dépasse par la droite, on avance la caméra
else if (cxperso > xlimmax)
{
setStartX(getStartX() + 4);
}
 
//Si on arrive au bout de la map à gauche, on stoppe le scrolling
if (getStartX() < 0)
{
setStartX(0);
}
 
//Si on arrive au bout de la map à droite, on stoppe le scrolling à la
//valeur Max de la map - la moitié d'un écran (pour ne pas afficher du noir).
else if (getStartX() + SCREEN_WIDTH >= getMaxX())
{
setStartX(getMaxX() - SCREEN_WIDTH);
}
 
//Si on dépasse par le haut, on remonte la caméra
if (cyperso < ylimmin)
{
setStartY(getStartY() - 4);
}
 
//Si on dépasse par le bas, on descend la caméra
if (cyperso > ylimmax)
{
//Sauf si on tombe très vite, auquel cas, on accélère la caméra :
if (player.dirY >= MAX_FALL_SPEED - 2)
{
setStartY(getStartY() + MAX_FALL_SPEED + 1);
}
else
{
setStartY(getStartY() + 4);
}
}
 
//Si on arrive au bout de la map en haut, on stoppe le scrolling
if (getStartY() < 0)
{
setStartY(0);
}
 
//Si on arrive au bout de la map en bas, on stoppe le scrolling à la
//valeur Max de la map - la moitié d'un écran (pour ne pas afficher du noir).
else if (getStartY() + SCREEN_HEIGHT >= getMaxY())
{
setStartY(getMaxY() - SCREEN_HEIGHT);
}
 
}
   Dans cette fonction, j'ai changé 2 choses :
1. La vitesse de la caméra que j'ai portée à 4 pour avoir un caméraman un peu plus nerveux, dopé à la caféine ! laugh
2. Comme notre héros va maintenant pouvoir se tuer en tombant dans les trous (comme un...), j'ai créé un petit effet de retour en arrière sympa avec la caméra. Pour cela, on détecte si la caméra est à plus d'un écran de distance du héros. Si c'est le cas, c'est certainement parce qu'il est mort et qu'on vient de le ressusciter à l'autre bout de la map. On accélère alors la caméra à 30 pixels / frame pour qu'elle fasse un retour rapide sur notre héros. Mais attention, comme plus tard, on pourra sauvegarder à un checkpoint et revenir se tuer en arrière, il faut que la caméra gère les deux sens ! wink

   Il est maintenant temps de mettre à jour notre fonction initializePlayer() :

Fichier : player.c : Remplacez la fonction précédente par :

void initializePlayer(int newLevel)
{
 
//PV à 3
player.life = 3;
 
//Timer d'invincibilité à 0
player.invincibleTimer = 0;
 
//Indique l'état et la direction de notre héros
player.direction = RIGHT;
player.etat = IDLE;
 
//Indique le numéro de la frame où commencer
player.frameNumber = 0;
//...la valeur de son chrono ou timer
player.frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
//... et son nombre de frames max (8 pour l'anim' IDLE
// = ne fait rien)
player.frameMax = 8;
 
player.x = getBeginX();
player.y = getBeginY();
 
//On réinitiliase les coordonnées de la caméra
//si on change de niveau
if (newLevel == 1)
{
setStartX(getBeginX());
setStartY(getBeginY());
}
 
/* Hauteur et largeur de notre héros */
player.w = PLAYER_WIDTH;
player.h = PLAYER_HEIGTH;
 
//Variables nécessaires au fonctionnement de la gestion des collisions
player.timerMort = 0;
player.onGround = 0;
 
}

   Afin que notre petit effet de caméra ne se produise que quand on meurt et pas quand on commence un niveau, il nous faut modifier cette fonction, pour qu'elle prenne en argument une nouvelle variable newLevel. Si celle-ci vaut 1, on commence un nouveau niveau et on réinitialise la caméra, sinon non.

   Il nous faut donc changer ses appels dans le main() en rajoutant 1 comme argument (sinon, c'est 0 dans les fonctions ci-dessus wink) :

Fichier : main.c : Modifiez l'appel à initializePlayer() :

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);

 

   Passons maintenant à notre fameuse fonction mapCollision() située dans le fichier map.c.

   Comme cette fonction est longue et complexe (mais aussi assez répétitive), j'ai préféré la commenter directement dans le code. C'est sans conteste, l'une des fonctions les plus complexes que nous ayions vues jusqu'ici. Ne vous inquiétez donc pas si vous ne comprenez pas tout du premier coup, nous y reviendrons par la suite. wink

   Pour faire simple, elle décortique notre sprite en blocs correspondant chacun à une tile pour voir quelles tiles le sprite recouvre. Si celles-ci sont traversables (blank), c'est OK, sinon, elle stoppe le sprite en le collant contre les tiles solides.  

   Je vous laisse lire les commentaires :

Fichier : map.c : Ajoutez la fonction :

void mapCollision(GameObject *entity)
{
 
int i, x1, x2, y1, y2;
 
/* D'abord, on considère le joueur en l'air jusqu'à temps
d'être sûr qu'il touche le sol */
entity->onGround = 0;
 
/* Ensuite, on va tester les mouvements horizontaux en premier
(axe des X). On va se servir de i comme compteur pour notre boucle.
En fait, on va découper notre sprite en blocs de tiles pour voir
quelles tiles il est susceptible de recouvrir.
On va donc commencer en donnant la valeur de Tile_Size à i pour qu'il
teste la tile où se trouve le x du joueur mais aussi la suivante SAUF
dans le cas où notre sprite serait inférieur à la taille d'une tile.
Dans ce cas, on lui donnera la vraie valeur de la taille du sprite
Et on testera ensuite 2 fois la même tile. Mais comme ça notre code
sera opérationnel quelle que soit la taille de nos sprites ! */
 
if (entity->h > TILE_SIZE)
i = TILE_SIZE;
else
i = entity->h;
 
 
//On lance alors une boucle for infinie car on l'interrompra selon
//les résultats de nos calculs
for (;;)
{
//On va calculer ici les coins de notre sprite à gauche et à
//droite pour voir quelle tile ils touchent.
x1 = (entity->x + entity->dirX) / TILE_SIZE;
x2 = (entity->x + entity->dirX + entity->w - 1) / TILE_SIZE;
 
//Même chose avec y, sauf qu'on va descendre au fur et à mesure
//pour tester toute la hauteur de notre sprite, grâce à notre
//fameuse variable i.
y1 = (entity->y) / TILE_SIZE;
y2 = (entity->y + i - 1) / TILE_SIZE;
 
//De là, on va tester les mouvements initiés dans updatePlayer
//grâce aux vecteurs dirX et dirY, tout en testant avant qu'on
//se situe bien dans les limites de l'écran.
if (x1 >= 0 && x2 < MAX_MAP_X && y1 >= 0 && y2 < MAX_MAP_Y)
{
//Si on a un mouvement à droite
if (entity->dirX > 0)
{
//On vérifie si les tiles recouvertes sont solides
if (map.tile[y1][x2] > BLANK_TILE || map.tile[y2][x2] > BLANK_TILE)
{
// Si c'est le cas, on place le joueur aussi près que possible
// de ces tiles, en mettant à jour ses coordonnées. Enfin, on
//réinitialise son vecteur déplacement (dirX).
 
entity->x = x2 * TILE_SIZE;
entity->x -= entity->w + 1;
entity->dirX = 0;
 
}
}
 
//Même chose à gauche
else if (entity->dirX < 0)
{
if (map.tile[y1][x1] > BLANK_TILE || map.tile[y2][x1] > BLANK_TILE)
{
entity->x = (x1 + 1) * TILE_SIZE;
entity->dirX = 0;
}
 
}
 
}
 
//On sort de la boucle si on a testé toutes les tiles le long de la hauteur du sprite.
if (i == entity->h)
{
break;
}
 
//Sinon, on teste les tiles supérieures en se limitant à la heuteur du sprite.
i += TILE_SIZE;
 
if (i > entity->h)
{
i = entity->h;
}
}
 
 
//On recommence la même chose avec le mouvement vertical (axe des Y)
if (entity->w > TILE_SIZE)
i = TILE_SIZE;
else
i = entity->w;
 
 
for (;;)
{
x1 = (entity->x) / TILE_SIZE;
x2 = (entity->x + i) / TILE_SIZE;
 
y1 = (entity->y + entity->dirY) / TILE_SIZE;
y2 = (entity->y + entity->dirY + entity->h) / TILE_SIZE;
 
if (x1 >= 0 && x2 < MAX_MAP_X && y1 >= 0 && y2 < MAX_MAP_Y)
{
if (entity->dirY > 0)
{
/* Déplacement en bas */
 
//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
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;
}
 
}
 
else if (entity->dirY < 0)
{
 
/* Déplacement vers le haut */
if (map.tile[y1][x1] > BLANK_TILE || map.tile[y1][x2] > BLANK_TILE)
{
entity->y = (y1 + 1) * TILE_SIZE;
entity->dirY = 0;
}
 
}
}
 
//On teste la largeur du sprite (même technique que pour la hauteur précédemment)
if (i == entity->w)
{
break;
}
 
i += TILE_SIZE;
 
if (i > entity->w)
{
i = entity->w;
}
}
 
/* Maintenant, on applique les vecteurs de mouvement si le sprite n'est pas bloqué */
entity->x += entity->dirX;
entity->y += entity->dirY;
 
//Et on contraint son déplacement aux limites de l'écran.
if (entity->x < 0)
{
entity->x = 0;
}
 
else if (entity->x + entity->w >= map.maxX)
{
//Si on touche le bord droit de l'écran, on annule
//et on limite le déplacement du joueur
entity->x = map.maxX - entity->w - 1;
}
 
//Maintenant, s'il sort de l'écran par le bas (chute dans un trou sans fond), on lance le timer
//qui gère sa mort et sa réinitialisation (plus tard on gèrera aussi les vies).
if (entity->y > map.maxY)
{
entity->timerMort = 60;
}
}

   Ouf ! C'était une bonne grosse fonction ! cheeky

   Ne vous inquiétez pas trop si vous n'êtes pas encore trop à l'aise avec, car nous allons souvent revenir dessus pour implémenter nos nouvelles tiles spéciales, au fur et à mesure. En effet, pour l'instant, elle ne gère que les tiles traversables, solides et plateformes (qu'on ne teste en fait qu'une fois : dans la direction vers le bas wink).

   Pour finir, on met à jour nos 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 cleanMaps(void);
extern void cleanPlayer(void);
extern void cleanup(void);
extern void delay(unsigned int frameLimit);
extern void drawGame(void);
extern void drawImage(SDL_Texture *, int, int);
extern void drawMap(int);
extern void drawPlayer(void);
extern void drawTile(SDL_Texture *image, int destx, int desty, int srcx, int srcy);
extern void gestionInputs(Input *input);
extern SDL_Texture *getBackground(void);
extern int getBeginX(void);
extern int getBeginY(void);
extern void getInput(Input *input);
extern int getLevel(void);
extern int getMaxX(void);
extern int getMaxY(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 void init(char *);
extern void initializePlayer(int newLevel);
extern void initMaps(void);
extern void initPlayerSprites(void);
extern void loadGame(void);
extern SDL_Texture *loadImage(char *name);
extern void loadMap(char *name);
extern void mapCollision(GameObject *entity);
extern void setNombreDeVies(int valeur);
extern void setNombreDetoiles(int valeur);
extern void setStartX(int valeur);
extern void setStartY(int valeur);
extern void SetValeurDuNiveau(int valeur);
extern void updatePlayer(Input *input);
 
 
#endif

   Voilà, plus qu'à compiler et à lancer le programme ! wink

   Notre héros peut maintenant se balader dans la map et sauter comme un cabri ! angel Cool ! cool

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

                                                                            Jay 

 

 

 

Connexion

CoalaWeb Traffic

Today115
Yesterday282
This week909
This month3202
Total1742409

19/04/24