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.

 

 
 

 

 

Big Tuto SDL 2 : Rabidja v. 3.0

Chapitre 8 : Ajoutons notre héros : Rabidja !

 

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

Dernière mise à jour : 9 novembre 2015

 

      Prologue

   Bon, maintenant que vous avez eu le temps de faire un peu mumuse avec le level editor, indecision retournons aux choses sérieuses ! laugh

   Nous allons maintenant ajouter notre héros, à savoir le lapin-ninja : Rabidja ! cool

   Dans ce chapitre, nous allons le créer, grâce à une nouvelle structure : la structure GameObject, qui ne sera pas spécifique à notre héros, mais sera employée de façon universelle par tous nos sprites, y compris : les monstres, les plateformes mobiles, les shurikens, etc.

   Mais quel est l'avantage de faire cela ? frown

   Eh bien, d'uniformiser au maximum pour réduire les risques d'erreurs. Qui plus est, ce sera ensuite plus facile de comparer des objets identiques, dans le cadre de la détection des collisions, par exemple. On pourra ainsi créé une fonction qui teste les collisions entre 2 GameObjects, quels qu'ils soient, et on pourra ensuite lui envoyer le joueur et un monstre ou un monstre et un shuriken, etc...

   Et pour afficher notre héros, nous allons aussi avoir besoin d'une spritesheet, que je vais vous donner ! cheeky

Mais, c'est quoi une spritesheet ? frown

C'est une feuille de sprites en français, c'est-à-dire un fichier image (au format png de préférence car il est non destructeur, pas comme le jpg) qui reprend toutes les animations de notre héros.
Ce sera ensuite à nous de découper cette feuille dans notre fonction de dessin draw() pour afficher les animations correctement. wink

Si vous avez déjà lu le Big Tuto SDL 1.2 / 2, vous verrez que j'ai très nettement amélioré la gestion des animations dans cette version de Rabidja, et que le programme consommera nettement moins de ressources qu'auparavant. 

Enfin, si vous voulez en apprendre un peu plus sur le pixel art pour créer votre héros, vous pourrez lire ces quelques chapitres, même si, aujourd'hui, ils datent un peu... cheeky

   Bon, voilà donc notre spritesheet : 

   Vous aurez certainement reconnu Rabidja et vous aurez remarqué 5 lignes. wink

   A chaque ligne correspond une animation, et il nous faudra donc afficher les frames de la bonne ligne en fonction de l'état de notre héros. En effet :
- ligne 0 : il reste passif sans bouger (état IDLE),
- ligne 1 : il marche (état WALK),
- ligne 2 : il saute (état JUMP),
- ligne 3 : il fait un double saut en salto (état JUMP2),
- ligne 4 : il meurt (cet état sera peut-être implémenté plus tard : DEAD).

   Vous aurez aussi remarqué que chaque anim' n'est pas de la même longueur : il faudra aussi y faire attention ! cheeky

   Maintenant, avant de passer au code à proprement dit, vous pouvez charger les archives complètes du jeu ci-dessous wink :

 

 

      Le code

   Nous allons d'abord commencer par rajouter quelques nouvelles defs dont nous allons avoir besoin par la suite.

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

Fichier : defs.h : Rajoutez :

#define TIME_BETWEEN_2_FRAMES_PLAYER 4
 
/* Taille du sprite de notre héros (largeur = width et hauteur = heigth) */
#define PLAYER_WIDTH 40
#define PLAYER_HEIGTH 50
 
//Vitesse de déplacement en pixels du sprite
#define PLAYER_SPEED 4
 
//Valeurs attribuées aux états/directions
#define IDLE 0
#define WALK 1
#define JUMP1 2
#define JUMP2 3
#define DEAD 4
 
#define RIGHT 1
#define LEFT 2

   On y trouve tout d'abord un nouveau timer plus faible, pour calculer l'écart entre 2 frames de l'animation de notre héros. Vous pourrez vous amuser à changer cette valeur pour voir son incidence sur la vitesse d'animation du personnage. wink

   On trouve ensuite les dimensions d'un sprite de notre héros qui fait 50 pixels de haut pour 40 pixels de large.

   PLAYER_SPEED nous servira dans un futur chapitre pour calculer la vitesse de déplacement de notre héros. Mais, tant qu'à faire, on le prévoit dès maintenant ! wink

   Ensuite, on trouve une sorte d'enum qui reprend (si vous avez bien suivi) les différentes lignes de notre spritesheet. Ainsi, l'état du perso aura une valeur (0, 1, 2, 3 ou 4) qui nous permettra de calculer directement la ligne à utiliser pour son animation sur la feuille de sprite. C'est simple et astucieux, comme système. wink

   Les deux dernières valeurs nous permettront de savoir dans quelle direction se déplace le joueur pour savoir si l'on doit effectuer un flip (retournement) sur nos sprites ou non. En effet, si vous avez déjà lu le Big Tuto SDL 1.2 / 2, vous devez vous rappeler que pour chaque anim', on en avait une orientée à droite et une autre à gauche. En SDL2, nous n'en avons plus besoin, car elle gère nativement le flip (horizontal et vertical), et cela sans que l'on perde quoi que ce soit au niveau de la vitesse d'exécution du programme ! cool

   Passons maintenant à notre fichier structs.h, dans lequel nous allons rajouter notre nouvelle structure GameObject, dont je vous ai parlé précédemment :

Fichier : structs.h : Rajouter : 

// Structure pour gérer nos sprites
typedef struct GameObject
{
 
// Points de vie/santé + chrono d'invicibilité
int life, invincibleTimer;
 
// Coordonnées du sprite
int x, y;
 
// Largeur, hauteur du sprite
int h, w;
 
// Checkpoint pour le héros (actif ou non)
int checkpointActif;
// + coordonnées de respawn (réapparition)
int respawnX, respawnY;
 
 
// Variables utiles pour l'animation :
// Numéro de la frame (= image) en cours + timer
int frameNumber, frameTimer, frameMax;
// Nombre max de frames, état du sprite et direction
// dans laquelle il se déplace (gauche / droite)
int etat, direction;
 
 
// Variables utiles pour la gestion des collisions :
//Est-il sur le sol, chrono une fois mort
int onGround, timerMort;
//Vecteurs de déplacement temporaires avant détection
//des collisions avec la map
float dirX, dirY;
//Sauvegarde des coordonnées de départ
int saveX, saveY;
 
//Variable pour le double saut
int jump;
 
 
} GameObject;

   J'ai déjà largement commenté dans le code chacune de ces variables, qui seront pour la plupart assez génériques. wink

   On commence donc par les points de vie de notre héros (qui débutera avec 3 coeurs, comme c'est original ! laugh) et un chrono (timer) qui nous permettra de le rendre invincible pendant un court instant, après s'être fait toucher (sinon, à 60 fps, il perdrait ses 3 coeurs en 3 frames, soit 3 / 60ème de seconde ! surprise Je sais que vos réflexes de gamer sont affutés, mais quand même ! laugh).

   Ensuite viennent les coordonnées de notre héros et ses dimensions (que nous avons entrées en defines wink).

   Les variables suivantes nous permettront plus tard de gérer les checkpoints de mi-niveau pour éviter de tout recommencer dès le début à chaque fois qu'on meurt ! Ce sera cool, mais ce n'est pas encore pour tout de suite ! wink

   Les variables d'animation, par contre, vont nous servir dès ce niveau : frameNumber contiendra le numéro de la frame (ou image) affichée en ce moment, frameTimer le temps restant avant le passage à la prochaine frame, et frameMax indiquera le numéro de la dernière frame de l'animation après laquelle on doit revenir à la première. wink

   Etat et direction contiendront les valeurs que nous avons définies en defines et nous permettront de retrouver l'animation en cours (idle, walk, jump, etc...) ainsi que la direction que prend le perso (right / left).

   Les variables suivantes vont nous servir dans les chapitres suivants et nous permettront de gérer la physique du joueur : onGround nous indiquera si les pieds du héros touchent le sol ou pas (auquel cas, il doit tomber cheeky).

   timerMort fera une petite tempo suite à la mort du joueur avant de le réinitialiser (histoire de laisser le temps au joueur de se rendre compte qu'il vient de trépasser comme un... indecision).

   dirX et dirY seront 2 vecteurs qui nous permettront de précalculer le déplacement optimal de notre héros avant détection des collisions. Cette valeur sera ensuite adaptée en conséquence (si notre héros devait se retrouver dans un mur, par exemple, on le collera plutôt contre celui-ci - c'est mieux ! laugh). Mais on verra ça dans un prochain chapitre. wink

   saveX et saveY nous serviront dans certains cas, pour vérifier si le sprite s'est déplacé ou pas depuis la frame précédente, en sauvegardant tout simplement sa position d'avant. On verra à quoi cela pourra bien nous servir. cheeky

   Enfin, la variable jump nous permettra de gérer le double saut de notre héros, car, oui, il pourra faire un double saut, comme dans (presque) tous les grands jeux de plateformes ! cool

 

   Bon, je pense avoir été assez exhaustif. Il faut savoir que j'ai choisi de mettre la quasi totalité de cette structure dès le début pour vous donner une vue d'ensemble sur ce que l'on va faire et sur ce que notre héros sera capable de faire. Bien entendu, il va nous falloir encore quelques chapitres avant d'exploiter toutes ces variables (on va y aller petit à petit wink), et nous en rajouterons même de nouvelles plus tard ! laugh

 

   Voilà, nos defs sont OK et notre structure est à jour, on va donc pouvoir attaquer du code, du vrai ! Et vous vous en doutez, l'essentiel va se passer dans notre fichier player.c, pour l'instant assez vide...

   Vous pouvez donc supprimer ce qu'on avait déjà mis et le remplacer par le code suivant (ou compléter ce qui vous manque, si vous souhaitez détailler davantage le code wink) : 

Fichier : player.c : Remplacer le contenu du fichier par : 

#include "prototypes.h"
 
 
 
int level;
GameObject player;
SDL_Texture *playerSpriteSheet;
 
 
//Renvoie le GameObject player (héros)
GameObject *getPlayer(void)
{
return &player;
}
 
 
//Renvoie les coordonnées x du héros
int getPlayerx(void)
{
return player.x;
}
 
 
//Renvoie les coordonnées y du héros
int getPlayery(void)
{
return player.y;
}
 
 
//Change la valeur des coordonnées x du héros
void setPlayerx(int valeur)
{
player.x = valeur;
}
 
 
//Change la valeur des coordonnées y du héros
void setPlayery(int valeur)
{
player.y = valeur;
}
 
 
//Renvoie le numéro du niveau en cours
int getLevel(void)
{
return level;
}
 
 
//Change la valeur du niveau en cours
void SetValeurDuNiveau(int valeur)
{
level = valeur;
}

   Nos fonctions concernant le niveau (level) sont toujours là, mais on déclare dorénavant en local, un GameObject player (joueur) et une SDL_Texture playerSpriteSheet qui contiendra la feuille de sprites de notre petit Rabidja. wink

   On a ensuite tout un paquet de fonctions get() et set() qui nous permettront de retrouver la valeur d'une variable ou de la modifier depuis un autre fichier du programme (puisque nos variables ne sont plus globales comme dans le Big Tuto SDL 1.2 / 2). cool

   C'est assez basique, et je passe rapidement dessus, car le gros du boulot nous attend, les gars ! laugh

   Mais ce n'est pas encore pour tout de suite... (comment ça : "Oh !!!! no" ?) angel

   D'abord, on va copier à la suite, ces deux fonctions qui nous permettront de charger notre spritesheet au début du jeu puis de la décharger en quittant (sinon, on n'y touchera pas wink) :

Fichier : player.c : Copier à la suite : 

//Charge la spritesheet (= feuille de sprites) de notre héros
//au début du jeu
void initPlayerSprites(void)
{
playerSpriteSheet = loadImage("graphics/rabidja.png");
}
 
 
//Libère le sprite du héros à la fin du jeu
void cleanPlayer(void)
{
if (playerSpriteSheet != NULL)
{
SDL_DestroyTexture(playerSpriteSheet);
playerSpriteSheet = NULL;
}
}

   On passe maintenant à l'initialisation de notre joueur, qui nous permettra de remettre à défaut ses valeurs, soit au début du jeu, soit quand on passera d'un niveau à un autre, soit quand on mourra et qu'on recommencera le niveau :

Fichier : player.c : Copier à la suite : 

void initializePlayer(void)
{
 
//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();
 
/* 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;
 
}

   Comme vous pouvez le voir, il n'y a rien de bien sorcier : on initialise ses Points de Vie à 3 coeurs, on charge l'animation IDLE (ne fait rien) vers la droite (car c'est dans cette direction que se situe la fin du niveau wink), on part de la frame 0, on initialise le timer (chrono) et on définit la frame Max de notre anim' à 8 (car c'est la première et qu'elle fait 8 images cheeky).

   On définit ensuite la position de départ du joueur par rapport aux variables map.beginX et map.beginY, qu'on a lu dans le fichier de la map précédemment (cf. chapitre 6) et qu'on appelle à l'aide des fonctions getBeginX() et getBeginY(), sinon on ne pourrait pas y avoir accès, sans transmission des pointeurs adéquats wink.

   On enregistre enfin la taille de notre sprite et on met le timer de résurrection (timerMort) à 0 ainsi que la position onGround (sur le sol). Cependant, comme on l'a dit auparavant, ces variables ne nous seront pas utiles dès ce chapitre (mais dans le prochain et celui d'après wink).

   Eh voilà ! Vous l'attendiez ! La grosse fonction qui va se charger de dessiner notre sprite à l'écran et de l'animer arrive :

Fichier : player.c : Copier à la suite :  

void drawPlayer(void)
{
/* Gestion du timer */
// Si notre timer (un compte à rebours en fait) arrive à zéro
if (player.frameTimer <= 0)
{
//On le réinitialise
player.frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
 
//Et on incrémente notre variable qui compte les frames de 1 pour passer à la suivante
player.frameNumber++;
 
//Mais si on dépasse la frame max, il faut revenir à la première :
if (player.frameNumber >= player.frameMax)
player.frameNumber = 0;
 
}
//Sinon, on décrémente notre timer
else
player.frameTimer--;
 
 
//Ensuite, on peut passer la main à notre fonction
 
/* Rectangle de destination à dessiner */
SDL_Rect dest;
 
// On soustrait des coordonnées de notre héros, ceux du début de la map, pour qu'il colle
//au scrolling :
dest.x = player.x - getStartX();
dest.y = player.y - getStartY();
dest.w = player.w;
dest.h = player.h;
 
/* Rectangle source */
SDL_Rect src;
 
//Pour connaître le X de la bonne frame à dessiner, il suffit de multiplier
//la largeur du sprite par le numéro de la frame à afficher -> 0 = 0; 1 = 40; 2 = 80...
src.x = player.frameNumber * player.w;
src.w = player.w;
src.h = player.h;
 
//On calcule le Y de la bonne frame à dessiner, selon la valeur de l'état du héros :
//Aucun Mouvement (Idle) = 0, marche (walk) = 1, etc...
//Tout cela en accord avec notre spritesheet, of course ;)
src.y = player.etat * player.h;
 
//Gestion du flip (retournement de l'image selon que le sprite regarde à droite ou à gauche
if (player.direction == LEFT)
SDL_RenderCopyEx(getrenderer(), playerSpriteSheet, &src, &dest, 0, 0, SDL_FLIP_HORIZONTAL);
else
SDL_RenderCopyEx(getrenderer(), playerSpriteSheet, &src, &dest, 0, 0, SDL_FLIP_NONE);
 
}
   La première partie de cette fonction s'occupe de gérer le timer ou chrono d'animation.
   Cela peut avoir l'air compliqué, mais en fait, c'est extrêmement simple :
- A chaque tour de boucle, on teste si notre compte à rebours (timer) arrive à 0 :
- Si c'est le cas : on réinitialise le timer à la valeur de la def. 
- Et on augmente la valeur de la frame (image) en cours de 1, pour passer à la suivante.
- Mais si on est rendu au bout de l'anim', on ne va pas blitter du vide ! surprise Donc, on revient à la frame 0wink
- Si ce n'est pas le cas, on décrémente notre compte à rebours de 1, et on continue. 

 

   C'est la méthode classique pour implémenter un timer et vous pourrez vous en inspirer pour bien d'autres usages, car il faut bien concevoir qu'un jeu vidéo fonctionne un peu comme une horloge et tout doit être savamment minuté pour que l'ensemble ait l'air cohérent. Cela n'en a pas forcément l'air comme ça, car on essaye de faire en sorte que le jeu ait l'air vivant et réaliste / logique, mais tout a été auparavant savamment orchestré par le game designer, le level designer et le programmeur (entre autres wink).

   On passe ensuite au dessin de notre sprite. Pour cela, on va avoir besoin de 2 rectangles :
- le rectangle de destination correspond à l'endroit de la map où on va blitter le joueur. Pour cela, on va avoir besoin de ses coordonnées dans le niveau, moins ceux du scrolling de la map (mais on verra ça plus tard, car pour l'instant, on n'a pas encore de scrolling, donc les coordonnées de la map correspondent à celles de l'écran wink). Et aussi de ses dimensions (largeur et hauteur définis précédemment).
- le rectangle source correspond à l'endroit de la feuille de sprite que l'on va copier (avec la bonne frame de préférence ! laugh).

Pour cela, notre largeur et notre hauteur vont être celles de la taille de notre sprite, soit 40 x 50, il n'y a pas de surprise. wink

Mais là, où il va falloir faire des calculs, c'est pour obtenir les bonnes coordonnées x et y :
- Ainsi, le x de la bonne frame va correspondre au numéro de la frame en cours (frameNumber) multiplié par la largeur d'une frame (40 pixels). Ainsi, la frame 0 sera à 0 x 40 = 0 pixel, la frame 1 à 1 x 40 = 40 pixels, la frame 2 à 2 x40 pixels = 80, etc...
- Et pour trouver le y, on va se servir de notre énum précédente : IDLE = 0, donc son anim' se trouve à 0 x 50 = 0 pixel, WALK = 1, donc son anim' se trouve à 1 x 50 = 50 pixels, etc...

Je pense que vous avez compris le système. wink C'est beaucoup plus simple et ingénieux ainsi, par rapport au système que nous utilisions dans le Big Tuto SDL 1.2 / 2 et cela nous fait gagner du temps et des ressources, car il est beaucoup moins coûteux de charger et découper de gros fichiers images que d'en charger plein de petits (croyez-moi, j'ai fait cramer une Xbox 360, comme ça cheeky) ! wink

   Voilà, une fois qu'on a défini nos deux rectangles, il ne nous reste plus qu'à blitter notre sprite. Pour cela, nous utilisons SDL_RenderCopyEx() qui nous permet de blitter en gérant les rotations de sprites et le flip. La rotation ne nous intéresse pas ici et vaudra donc 0, mais le flip va nous permettre de retourner notre sprite horizontalement en fonction de sa direction. Ainsi, on n'a plus besoin d'avoir deux feuilles de sprites, une pour chaque direction, comme en SDL 1.2 ! cool

 

   C'était donc le plus gros de ce chapitre ! Passons maintenant à l'intégration de notre joueur dans le reste du code ! 

   On va commencer par faire un tour dans le fichier map.c pour ajouter quelques fonctions qui vont nous être utiles pour retrouver ou changer certaines valeurs de base à l'aide de get(), set() :

Fichier : .c : map.c : Rajouter :

 
int getStartX(void)
{
return map.startX;
}
 
void setStartX(int valeur)
{
map.startX = valeur;
}
 
int getStartY(void)
{
return map.startY;
}
 
void setStartY(int valeur)
{
map.startY = valeur;
}
 
int getMaxX(void)
{
return map.maxX;
}
 
int getMaxY(void)
{
return map.maxY;
}
 
int getBeginX(void)
{
return map.beginx;
}
 
int getBeginY(void)
{
return map.beginy;
}
 

   Il n'y a rien de plus à dire ici, passons donc à notre fichier init.c :

Fichier : init.c : Modifier :

void loadGame(void)
{
 
//On charge les données pour la map
initMaps();
 

//NOUVEAU : On charge la feuille de sprites (spritesheet) de notre héros

initPlayerSprites();

 
//On commence au premier niveau
SetValeurDuNiveau(1);
changeLevel();
 
}
 
 
void cleanup()
{
//Nettoie les sprites de la map
cleanMaps();
 

//NOUVEAU : Libère le sprite du héros 

cleanPlayer();

 
//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();
}

   Ici, on rajoute simplement les appels à initPlayerSprites() pour charger la feuille de sprites au début du jeu, dans loadGame(), et cleanPlayer() pour la décharger proprement dans cleanup().

   Passons à notre fichier draw.c :

Fichier : draw.c : Modifier : 

void drawGame(void)
{
// 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 la map de tiles : layer 3 (couche en foreground / devant) */
drawMap(3);
 
// Affiche l'écran
SDL_RenderPresent(getrenderer());
 
// Délai pour laisser respirer le proc
SDL_Delay(1);
}

   Idem, on rajoute un appel à notre fonction drawPlayer() dans la fonction drawGame().

Attention : on affiche bien le joueur après les couches (layers) 2 (background / fond) et 1 (scène / action) MAIS avant la couche 3 qui est celle du foreground (décor devant), pour qu'il puisse passer derrière. wink

   Passons maintenant au main.c !

Fichier : main.c : Modifier : 

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();
 
// Appelle la fonction cleanup à la fin du programme
atexit(cleanup);
 
   // Etc...

   Voilà, on rajoute ici un appel à notre fonction initializePlayer() dans le début du main. wink

Vous remarquerez qu'avec la nouvelle architecture du code dans ce nouveau Big Tuto, chaque point-clef du jeu (comme ici la gestion du player ou avant de la map) est encore plus encapsulé qu'avant dans un fichier spécifique. Il suffit ensuite de relier ses fonctions principales (en général : Init(), Update(), Draw() et Clean()) dans la boucle de base du jeu. Le code est ainsi plus facilement réutilisable pour vos propres projets, puisqu'il suffit d'y insérer le fichier voulu et d'inclure les appels à ses fonctions clefs dans votre propre code. wink

   Allez, on a presque fini ! Plus que notre catalogue de prototypes à mettre à jour !

Fichier : prototypes.h : Remplacer 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 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(void);
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 setNombreDeVies(int valeur);
extern void setNombreDetoiles(int valeur);
extern void SetValeurDuNiveau(int valeur);
 
 
#endif

   Comme, vous pouvez le constater, il commence à prendre du volume, et ce n'est pas fini ! laugh

   Et voilà, plus qu'à compiler et Tadaaaa ! surprise

                                                Notre héros s'affiche et s'anime ! angel

   Mais, mais !!?!! frown Il ne touche pas le sol !! surprise Et il ne bouge pas non plus !!!!!! angry

   Eh oui, c'est normal, on ne l'a pas encore programmé tout ça ! cheeky Il nous reste encore du chemin à parcourir avant de pouvoir le déplacer et gérer les collisions avec la map ! indecision

   Alors, @ bientôt pour la suite ! angel

                                                Jay.

 

 

 

Connexion

CoalaWeb Traffic

Today54
Yesterday232
This week1080
This month3373
Total1742580

20/04/24