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




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

Dernière mise à jour : 15 octobre 2011

Difficulté :  





Chapitre 18

Notre premier power-up
!


    Il va être maintenant temps d'ajouter notre premier power-up !
    Cela fait déjà un moment que notre lapin favori se promène parmi plein de petites étoiles... mais il est trop %$/# pour les ramasser !

    Heureusement, l'heure de la vengeance a sonné !


    Go ! Go ! Go !
   


Résultat à la fin de ce chapitre : notre lapin fait la chasse aux étoiles !



    Mais comment on va faire ?  Cela va faire mal ?

    Mais non, ce sera indolore pour notre petit lapin, rassurez-vous !  

    Ce qu'il va falloir faire, c'est modifier notre fonction mapCollision() qui gère les collisions du joueur avec la map.
    On va donc rajouter un test pour détecter les collisions avec la tile Etoile. Si c'est le cas, on remplacera cette tile par la tile 0 (transparente) dans notre tableau de tiles, et on incrémentera notre compteur d'étoiles de +1 dans une fonction getItem().

    Alors, c'est pas si compliqué que ça, non ?!


Nom du fichier : map.c


  void mapCollision(GameObject *entity)
{

    int i, x1, x2, y1, y2;

    entity->onGround = 0;

    if(entity->h > TILE_SIZE)
        i = TILE_SIZE;
    else
        i = entity->h;

    for (;;)
    {
       
        x1 = (entity->x + entity->dirX) / TILE_SIZE;
        x2 = (entity->x + entity->dirX + entity->w - 1) / TILE_SIZE;

        y1 = (entity->y) / TILE_SIZE;
        y2 = (entity->y + i - 1) / TILE_SIZE;

        if (x1 >= 0 && x2 < MAX_MAP_X && y1 >= 0 && y2 < MAX_MAP_Y)
        {
            //Si on a un mouvement à droite
            if (entity->dirX > 0)
            {

                //Test de la tile Power-up : Etoile (= tile N°5)
                if (map.tile[y1][x2] == 5)
                {
                    //On appelle la fonction getItem()
                    getItem();

                    //On remplace la tile power-up par une tile transparente
                    map.tile[y1][x2] = 0;
                }
                else if(map.tile[y2][x2] == 5)
                {
                    //On appelle la fonction getItem()
                    getItem();
                    //On remplace la tile power-up par une tile transparente
                    map.tile[y2][x2] = 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)
            {

                //Test de la tile Power-up : Etoile (= tile N°5)
                if (map.tile[y1][x1] == 5)
                {
                    //On appelle la fonction getItem()
                    getItem();

                    //On remplace la tile power-up par une tile transparente
                    map.tile[y1][x1] = 0;
                }
                else if(map.tile[y2][x1] == 5)
                {
                    //On appelle la fonction getItem()
                    getItem();
                    //On remplace la tile power-up par une tile transparente
                    map.tile[y2][x1] = 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 */
               
                //Test de la tile Power-up : Etoile (= tile N°5)
                if (map.tile[y2][x1] == 5)
                {
                    //On appelle la fonction getItem()
                    getItem();

                    //On remplace la tile power-up par une tile transparente
                    map.tile[y2][x1] = 0;
                }
                else if(map.tile[y2][x2] == 5)
                {
                    //On appelle la fonction getItem()
                    getItem();
                    //On remplace la tile power-up par une tile transparente
                    map.tile[y2][x2] = 0;
                }
               
               
                if (map.tile[y2][x1] > BLANK_TILE || map.tile[y2][x2] > BLANK_TILE)
                {
                    //Si la tile est 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 */
               
                //Test de la tile Power-up : Etoile (= tile N°5)
                if (map.tile[y1][x1] == 5)
                {
                    //On appelle la fonction getItem()
                    getItem();

                    //On remplace la tile power-up par une tile transparente
                    map.tile[y1][x1] = 0;
                }
                else if(map.tile[y1][x2] == 5)
                {
                    //On appelle la fonction getItem()
                    getItem();
                    //On remplace la tile power-up par une tile transparente
                    map.tile[y1][x2] = 0;
                }
               

                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, comme avant.
    if (entity->x < 0)
    {
        entity->x = 0;
    }

    else if (entity->x + entity->w >= map.maxX)
    {
        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;
    }
}

         

   
    Bon, d'accord, ce qu'il ne faut pas oublier c'est d'ajouter le test selon les 4 direction (haut, bas, gauche, droite), mais, avouez que c'est quand même pas bien sorcier !

    Bon, il est temps maintenant de programmer notre fonction getItem(). On va la mettre dans le fichier player.c, parce que c'est lui que ça concerne (quand même !)


    Dans cette fonction, on va donc incrémenter notre compteur d'étoiles et comme, on est géniaux , on va même faire gagner une vie à notre lapin quand on atteint 100 étoiles ! Alors, elle est pas belle la vie ?!

Nom du fichier : player.c


   void getItem(void)
{
    //On incrémente le compteur Etoile
    jeu.etoiles++;

    //On teste s'il y a 100 étoiles : on remet le compteur à 0 et on rajoute une vie ;)
    if ( jeu.etoiles >= 100 )
    {
        jeu.etoiles = 0;
        jeu.vies++;
    }
}


    Et on n'oublie pas de mettre à jour notre en-tête, s'il vous plaît !


Nom du fichier : map.h


  #include "structs.h"

   /* Prototypes des fonctions utilisées */
   extern void drawImage(SDL_Surface *, int, int);
   extern void drawTile(SDL_Surface *image, int destx, int desty, int srcx, int srcy);
   extern void initializeMonster(int x, int y);
   extern void getItem(void);

   extern Gestion jeu;
   extern Map map;

         


    Et voilà, vous pouvez compiler ! Magie, ça marche !
    Avouez quand même que ça avait l'air bien plus dur à faire que ça ne l'était !


    Vous remarquerez quand même qu'on peut maintenant gagner des vies, mais on n'en perd pas en mourant !
    Ouah ! Réparons cette injustice !



Nom du fichier : player.c


 void updatePlayer(void)
{

  if (player.timerMort == 0)
  {

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

   
     if (input.left == 1)
    {
        player.dirX -= PLAYER_SPEED;
        player.direction = LEFT;

        if(player.etat != WALK_LEFT && player.onGround == 1)
        {
            player.etat = WALK_LEFT;
            changeAnimation(&player, "graphics/walkleft.png");
        }
    }

    else if (input.right == 1)
    {
        player.dirX += PLAYER_SPEED;
        player.direction = RIGHT;

        if(player.etat != WALK_RIGHT && player.onGround == 1)
        {
            player.etat = WALK_RIGHT;
            changeAnimation(&player, "graphics/walkright.png");
        }
    }

    //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)
        {
            player.etat = IDLE;
            //On change l'animation selon la direction
            if(player.direction == LEFT)
            {
                changeAnimation(&player, "graphics/IdleLeft.png");
            }
            else
            {
                changeAnimation(&player, "graphics/IdleRight.png");
            }

        }

    }


    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)
    {
        if(player.direction == RIGHT && player.etat != JUMP_RIGHT)
        {
            player.etat = JUMP_RIGHT;
            changeAnimation(&player, "graphics/JumpRight.png");
        }
        else if(player.direction == LEFT && player.etat != JUMP_LEFT)
        {
            player.etat = JUMP_LEFT;
            changeAnimation(&player, "graphics/JumpLeft.png");
        }

    }

    mapCollision(&player);
    centerScrollingOnPlayer();

  }

    if (player.timerMort > 0)
    {
        player.timerMort--;

        if (player.timerMort == 0)
        {
            /* Si on est mort */
            jeu.vies--;
            if(jeu.vies < 0)
                jeu.vies = 0;
            initializePlayer();
        }
    }

}

         


    Voilà, il suffisait de rajouter 3 lignes !
    On décrémente notre compteur de vies à chaque mort, et à 0, bah on bloque le compteur car on n'a pas encore de menu Game Over ! (Et ça fait quand même mieux que Vies : -10 ! )

    Bon, voilà une bonne chose de faite ! Maintenant, dans le prochain chapitre, on va gérer le ressort et l'animation de la map (pour que l'eau bouge, les étoiles flottent, etc.) !

 
   


   




 

 

 

Connexion

CoalaWeb Traffic

Today81
Yesterday185
This week81
This month5251
Total1744458

29/04/24