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

 

 
 



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



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

Dernière mise à jour : 15 décembre 2013

Difficulté :  




10. Déplaçons notre héros !


    Il est temps maintenant de prendre le contrôle de notre héros ! Pour cela, nous allons désactiver les commandes du scrolling et les relier au déplacement de notre sprite. C'est parti !
 


Résultat à la fin de ce chapitre :
on peut déplacer notre héros à droite et à gauche et le scrolling et l'animation suivent 
!



    Là encore, nous allons procéder par étapes. Dans ce chapitre, nous allons relier les commandes au déplacement latéral de notre sprite, puis dans les chapitres suivants, nous nous occuperons des collisions avec la map d'une part, puis de la gestion des sauts d'autre part.


A. Prenons le contrôle de notre lapin !

    Premièrement, nous allons supprimer la fonction update gérant le scrolling dans input.c, et la remplacer par la fonction updatePlayer(), dans le fichier player.c :

Nom du fichier : player.c


 void updatePlayer(void)
{

     if (input.left == 1)
    {
        player.x -= PLAYER_SPEED;
       
        if (player.x < 0)
        {
            player.x = 0;
        }
    }

    else if (input.right == 1)
    {
        player.x += PLAYER_SPEED;
       
        if (player.x + PLAYER_WIDTH >= map.maxX)
        {
            player.x = map.maxX - PLAYER_WIDTH;;
        }

    }
   
}



    Bon, cette fonction est très simple car elle reprend grosso-modo notre fonction update précédente, à la différence près, qu'elle change les coordonnées de notre sprite et non plus de la map.

    La vitesse de notre héros est fixe et déterminée par la constante PLAYER_SPEED et on limite les coordonnées max de notre héros pour éviter qu'il ne sorte de la map (et tombe dans le vide intersidéral causant un bug infini comme ça pouvait arriver dans certain vieux (ou même pas si vieux que ça) jeux) !

    Ensuite, dans le main, nous allons remplacer la fonction update() par updatePlayer() (changement indiqué en bleu).

   

Nom du fichier : main.c


     while (go == 1)
    {

        /* On prend on compte les input (clavier, joystick... */
        getInput();

        /* On met à jour le jeu */
        updatePlayer();

        /* On affiche tout */
        draw();

        /* Gestion des 60 fps (1000ms/60 = 16.6 -> 16 */
        delay(frameLimit);
        frameLimit = SDL_GetTicks() + 16;

    }

 

    Puis, nous n'oublierons pas de mettre à jour le prototype dans main.h :

Nom du fichier : main.h

   #include "structs.h"

   /* Prototypes des fonctions utilisées */

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

   

     Et enfin, nous ajouterons, notre nouvelle constantes PLAYER_SPEED.
    Je l'ai mise à 4 par défaut, mais vous pourrez tester d'autres vitesses. Plus tard, on pourra aussi la faire varier en fonction de l'élan et de l'inertie du héros.

Nom du fichier : defs.h


   //Vitesse de déplacement en pixels du sprite
   #define PLAYER_SPEED 4


    Voilà ! Vous pouvez compiler et lancer le programme, et, Ô miracle ! Le lapin fou se déplace à gauche et à droite !!!
    Mais !! Attendez !! Le scrolling ne suit pas notre héros !!!
    Et, quand il fait demi-tour, il marche en arrière !

    Eh, oui ! C'est qu'on a encore un petit peu de boulot devant nous !


B. Centrons le scrolling sur notre lapin !

    Nous allons commencer par centrer notre scrolling sur le sprite de notre héros.
    Pour l'instant, nous allons nous contenter d'une fonction basique. Nous verrons plus tard comment l'améliorer .
    Reprenons donc le fichier player.c et ajoutons-y une nouvelle fonction : centerScrollingOnPlayer().
    Pour cela, c'est simple, nous allons prendre les coordonnées du joueur et y soustraire la taille d'un demi-écran. Comme ça, le joueur se retrouvera à peu près au centre de l'écran (on aurait aussi pu chipoter en prenant en compte la taille du sprite dans le calcul, mais bon... Comme de toutes façonc, nous complexifierons cette fonction plus tard...)
.


Nom du fichier : player.c

 
 void centerScrollingOnPlayer(void)
 {
    //On définit les coordonnées du début de l'affichage de la map par rapport à celles
    //du joueur.
    //Pour centrer le joueur, la map doit donc s'afficher à un demi-écran avant la position
    //du joueur.
    //Puis on "clamp" (limite) l'affichage de l'écran pour ne pas sortir de la map.
    map.startX = player.x - (SCREEN_WIDTH / 2);

    if (map.startX < 0)
    {
        map.startX = 0;
    }

    else if (map.startX + SCREEN_WIDTH >= map.maxX)
    {
        map.startX = map.maxX - SCREEN_WIDTH;
    }

    map.startY = player.y - (SCREEN_HEIGHT / 2);

    if (map.startY < 0)
    {
        map.startY = 0;
    }

    else if (map.startY + SCREEN_HEIGHT >= map.maxY)
    {
        map.startY = map.maxY - SCREEN_HEIGHT;
    }
 }


    Bon, il nous faut maintenant intégrer notre fonction quelque part, si on veut qu'elle serve à quelque chose. Et pourquoi pas dans updatePlayer() ? Cela semblerait logique, non ? 

   
Nom du fichier : player.c


 void updatePlayer(void)
{

     if (input.left == 1)
    {
        player.x -= PLAYER_SPEED;

        if (player.x < 0)
        {
            player.x = 0;
        }
    }

    else if (input.right == 1)
    {
        player.x += PLAYER_SPEED;

        if (player.x + PLAYER_WIDTH >= map.maxX)
        {
            player.x = map.maxX - PLAYER_WIDTH;;
        }

    }

    centerScrollingOnPlayer();

}


    Voilà, n'oublions pas de mettre à jour le prototype, sans quoi le compilateur risque de croire qu'on déclare 2 fois la même fonction (il est bête, celui là ! Les machines ne sont pas encore prêtes à prendre le contrôle de la terre... !  ) : 

 
   Nom du fichier : player.h
 

  #include "structs.h"

  extern Gestion jeu;
  extern Hero player;
  extern Input input;
  extern Map map;

  /* Prototypes des fonctions utilisées */
  extern SDL_Surface *loadImage(char *name);

  extern void centerScrollingOnPlayer(void);
   

     Maintenant on compile, on lance le programme et ** MAGIE ! ** le scrolling suit maintenant notre lapin, qui peut traverser la map !
    Oui, mais le demi-tour ne fonctionne toujours pas !
    Hey, minute ! On va maintenant mettre en place un système d'état pour savoir dans quel sens va notre lapin et changer son animation. Plus tard ce système nous sera aussi utile pour savoir s'il reste immobile, s'accroupit, saute, attaque, meurt, etc...

C. Créons un système d'états pour notre lapin !

    Pour cela, nous allons devoir compléter la structure Hero, en lui rajoutant une variable etat, et direction, pour savoir ce qu'il fait, et dans quelle direction il va !
    Bon, pour l'instant, c'est vrai qu'il ne fait que courir, donc c'est pas trop utile, mais ça le sera pour plus tard !!


Nom du fichier : structs.h


 /* Structure pour gérer notre héros */

  typedef struct Hero
  {
    //Sprite du héros (pas d'animation pour l'instant)
    SDL_Surface *sprite;

    /* Coordonnées du héros */
    int x, y;

    /* Variables utiles pour l'animation */
    int frameNumber, frameTimer;
    int etat, direction;

  } Hero;


 

    Nous allons aussi rajouter des constantes dans defs.h, à attribuer à ces variables (ce sera plus facile pour nous que d'utiliser directement des numéros).

Nom du fichier : defs.h


  //Valeurs attribuées aux états/directions
   #define WALK 1
   #define IDLE 2
   #define JUMP 3
   #define RIGHT 1
   #define LEFT 2

 

 
    Grâce à ces directives de préprocesseur, il nous suffira de faire :
if(direction == RIGHT)
au lieu d'un fastidieux
if(direction == 1)
pour lequel il faudrait se souvenir de la valeur de chaque état !...

    Bon, maintenant que notre structure est à jour, on va revoir l'initialisation de notre player pour nous assurer qu'il commence avec les bonnes valeurs :

Nom du fichier : player.c


  void initializePlayer(void)
  {

    /* Charge le sprite de notre héros */
    player.sprite = loadImage("graphics/walkright.png");
   
    //Indique l'état et la direction de notre héros
    player.direction = RIGHT;
    player.etat = WALK;
   
    //Réinitialise le timer de l'animation et la frame
    player.frameNumber = 0;
    player.frameTimer = TIME_BETWEEN_2_FRAMES;

    /* Coordonnées de démarrage de notre héros */
    player.x = 20;
    player.y = 304;

  }
   

    On le fait partir à droite, parce que dans la majorité des jeux de plateformes on va de droite à gauche (mais rien ne vous empêche de faire le contraire et de partir de la fin de la map !  ).
    On en profite aussi pour initialiser notre timer d'animation. Cela marchait sans, mais c'est quand même plus propres comme ça, et ça sera utile plus tard si on doit réinitialiser le jeu après une partie !
    Voilà, maintenant que c'est fait, on va pouvoir gérer tout ça dans notre fonction updatePlayer() !

Nom du fichier : player.c


void updatePlayer(void)
{

     if (input.left == 1)
    {
        player.x -= PLAYER_SPEED;

        if (player.x < 0)
        {
            player.x = 0;
        }

        //On teste le sens pour l'animation : si le joueur allait dans le sens contraire
        //précédemment, il faut recharger le spritesheet pour l'animation.
        if(player.direction == RIGHT)
        {
            player.direction = LEFT;
            player.sprite = loadImage("graphics/walkleft.png");
        }
    }

    else if (input.right == 1)
    {
        player.x += PLAYER_SPEED;

        if (player.x + PLAYER_WIDTH >= map.maxX)
        {
            player.x = map.maxX - PLAYER_WIDTH;;
        }

        if(player.direction == LEFT)
        {
            player.direction =  RIGHT;
            player.sprite = loadImage("graphics/walkright.png");
        }

    }

    centerScrollingOnPlayer();

}

    Alors en fait, c'est très simple, à chaque input, on va tester si notre joueur allait dans la direction inverse la fois d'avant. Si c'est le cas, alors on recharge le spritesheet contenant la bonne direction et on change la valeur de notre variable direction.
    Pour l'instant, vous remarquerez, qu'on ne se sert pas encore de notre variable etat. C'est normal puisque nous n'avons qu'un seul état pour l'instant, mais ça changera bientôt !

    Eh voilà, vous pouvez maintenant compiler puis lancer le programme ! Super lapin peut maintenant marcher à droite ou à gauche et le scrolling le suit !


      Bon, il flotte un peu en l'air parfois et passe au-travers des murs, mais nous allons régler ça au prochain chapitre !  

   


   





 

 

 

Connexion

CoalaWeb Traffic

Today46
Yesterday282
This week840
This month3133
Total1742340

19/04/24