Chapitre 34

Améliorons nos menus et notre jeu ! 

 

Tutoriel présenté par : Jérémie F. Bellanger (Jay)
Dernière mise à jour : 22 juillet 2014

 

   Dans ce nouveau chapitre, nous allons encore fignoler notre jeu, en améliorant tout d'abord les menus. En effet, le menu actuel nous fait systématiquement commencer au niveau 1, ce qui est relativement classique. wink

   Mais, voilà, si vous voulez créer 99 levels, voire même 999 ! devil En recommençant à 0 à chaque fois, et sans sauvegarde, ça va être difficile !... cheeky

   C'est pourquoi, nous allons d'abord rajouter la possibilité de choisir son niveau de 1 à LevelMax au menu de l'écran-titre.

   Ensuite, nous améliorerons un peu l'écran Pause en lui donnant la possibilité, soit de continuer le jeu, soit de retourner à l'écran-titre (pour changer de niveau par exemple wink).

   Et enfin, notre dernière amélioration, concernera le déplacement des zombies. En effet, vous aurez peut-être remarqué que nos zombies n'aiment pas, pour l'instant, se déplacer sur des plateformes traversables par le bas (pour le joueur), car le jeu les considère comme du vide (avec la variable BLANK_TILE). Nous verrons comment leur rétablir la possibilité de marcher sur les ponts et les toits des maisons et éviter des bugs, si vous essayez de les placer sur ces tiles. wink

   Allez, on est parti ! smiley

   

 

 

      Un nouveau menu d'écran-titre

   Et voici donc pour commencer les deux nouvelles fonctions permettant de changer l'écran-titre. cool

   Le plus simple, si vous mettez à jour votre projet au fur et à mesure, c'est de supprimer les 2 anciennes fonctions et de les remplacer par celles-ci. wink

 

Fichier : menu.c

void updateStartMenu(void)
{
    //Si on appuie sur BAS
    if(input.down == 1)
    {
        //Si choice = O (il est sur start), on le met à 1 (quit)
        if(jeu.choice == 0)
            jeu.choice++;

        input.down = 0;
    }

    //Si on appuie sur HAUT
    if(input.up == 1)
    {
        //Si choice = 1 (il est sur Quit), on le met à 0 (Start)
        if(jeu.choice == 1)
            jeu.choice--;

        input.up = 0;
    }

    //Choix du level
    if(input.right == 1)
    {
        //Si choice = 1 (il est sur Quit), on le met à 0 (Start)
        if(jeu.level > = LEVEL_MAX)
            jeu.level = 1;
        else
            jeu.level++;

        input.right = 0;
    }

    if(input.left == 1)
    {
        //Si choice = 1 (il est sur Quit), on le met à 0 (Start)
        if(jeu.level < = 1)
            jeu.level = LEVEL_MAX;
        else
            jeu.level--;

        input.left = 0;
    }



    //Si on appuie sur Enter ou A (manette Xbox 360) et qu'on est sur Start, on recharge le jeu et on quitte l'état menu
    if(input.enter || input.jump)
    {
         if(jeu.choice == 0)
        {
			player.checkpointActif = 0;
            //jeu.level = 1;
            initializePlayer();
            changeLevel();
            /* On réinitialise les variables du jeu */
            jeu.vies = 3;
            jeu.etoiles = 0;
            jeu.onMenu = 0;
        }
        //Sinon, on quitte le jeu
        else if(jeu.choice == 1)
        {
            exit(0);
        }
        input.enter = 0;
        input.jump = 0;
    }


}
    

 

void drawStartMenu(void)
{

    //On crée une variable qui contiendra notre texte
    char text[200];

	//On affiche l'écran-titre
	drawImage(map.titlescreen, 0, 0);

    //Le titre
    //sprintf(text, "Rabidja's Revenge");
	//drawString(text, 280, 50, font, 0, 0, 0, 255);

    //Si l'option n'est pas en surbrillance, on l'affiche normalement
    if(jeu.choice != 0)
    {
        sprintf(text, "START: Lvl %d", jeu.level);
		//Ombrage en noir
		drawString(text, 375, 252, font, 0, 0, 0, 255);
		drawString(text, 373, 250, font, 255, 255, 255, 255);
    }
    if(jeu.choice != 1)
    {
        sprintf(text, "QUIT");
		//Ombrage en noir
		drawString(text, 425, 292, font, 0, 0, 0, 255);
		drawString(text, 422, 290, font, 255, 255, 255, 255);
    }

     //Si l'option est en surbrillance, on change la couleur
    if(jeu.choice == 0)
    {
        sprintf(text, "START: Lvl %d", jeu.level);
		//Ombrage en noir
		drawString(text, 375, 252, font, 0, 0, 0, 255);
		drawString(text, 373, 250, font, 255, 255, 0, 255);
    }
    else if(jeu.choice == 1)
    {
        sprintf(text, "QUIT");
		//Ombrage en noir
		drawString(text, 425, 292, font, 0, 0, 0, 255);
		drawString(text, 422, 290, font, 255, 255, 0, 255);
    }

    //Le nom du studio
    //sprintf(text, "Meruvia Game Studio, 2014");
	//drawString(text, 230, 420, font, 0, 0, 0, 255);
}

 

   Et voilà, le code n'est pas bien compliqué comme vous pouvez le voir. wink

   On change simplement la valeur de jeu.level en appuyant sur Gauche/Droite à la 1ère ligne du menu, et on l'affiche. Le jeu démarrera ainsi à ce niveau-là. Vous remarquerez d'ailleurs que j'ai mis en commentaire l'ancienne ligne jeu.level = 1; . En effet, on ne veut plus démarrer toujours du niveau 1, mais du niveau choisi ! wink

 

Attention : Pour éviter un problème avec le surligneur syntaxique Geshi, j'ai dû séparer les chevrons >= et <= par un espace. N'oubliez pas de le supprimer, si vous faites du copier/coller. wink

 

      Un nouveau menu Pause

   Passons maintenant aux deux nouvelles fonctions permettant de changer le menu de Pause. cool

   Là encore, le plus simple sera de supprimer les 2 anciennes fonctions et de les remplacer par celles-ci. wink

 

Fichier : menu.c

void updatePauseMenu(void)
{

    //Si on appuie sur BAS
    if(input.down == 1)
    {
        //Si choice = O (il est sur start), on le met à 1 (quit)
        if(jeu.choice == 0)
            jeu.choice++;

        input.down = 0;
    }

    //Si on appuie sur HAUT
    if(input.up == 1)
    {
        //Si choice = 1 (il est sur Quit), on le met à 0 (Start)
        if(jeu.choice == 1)
            jeu.choice--;

        input.up = 0;
    }

    //Si on appuie sur Enter ou A (manette Xbox 360) et qu'on est sur Start, on recharge le jeu et on quitte l'état menu
    if(input.enter || input.jump)
    {
         if(jeu.choice == 0)
        {
			//Si on appuie sur Enter on quitte l'état menu
            jeu.onMenu = 0;
        }
        //Sinon, on quitte le jeu
        else if(jeu.choice == 1)
        {
            jeu.choice = 0;
            jeu.menuType = START;
        }
        input.enter = 0;
        input.jump = 0;
    }

}
    

 

void drawPauseMenu(void)
{
    char text[200];

    //On écrit PAUSE
    sprintf(text, "** PAUSE **");
	drawString(text, 322, 200, font, 0, 0, 0, 255);
	drawString(text, 320, 198, font, 255, 255, 255, 255);


    //Si l'option n'est pas en surbrillance, on l'affiche normalement
    if(jeu.choice != 0)
    {
        sprintf(text, "Continue");
		//Ombrage en noir
		drawString(text, 346, 252, font, 0, 0, 0, 255);
		drawString(text, 344, 250, font, 255, 255, 255, 255);
    }
    if(jeu.choice != 1)
    {
        sprintf(text, "Exit");
		//Ombrage en noir
		drawString(text, 386, 292, font, 0, 0, 0, 255);
		drawString(text, 384, 290, font, 255, 255, 255, 255);
    }

     //Si l'option est en surbrillance, on change la couleur
    if(jeu.choice == 0)
    {
        sprintf(text, "Continue");
		//Ombrage en noir
		drawString(text, 346, 252, font, 0, 0, 0, 255);
		drawString(text, 344, 250, font, 255, 255, 0, 255);
    }
    else if(jeu.choice == 1)
    {
        sprintf(text, "Exit");
		//Ombrage en noir
		drawString(text, 386, 292, font, 0, 0, 0, 255);
		drawString(text, 384, 290, font, 255, 255, 0, 255);
    }


}

 

   Là encore, le code n'est pas bien compliqué puisqu'il reprend grosso modo celui de l'écran-titre avec deux possibilités. wink

   Soit on reprend le jeu (comme dans le menu Pause précédent), soit on retourne à l'écran-titre en changeant simplement le menuType. cool

   Vous remarquerez aussi qu'on remet systématiquement les inputs à 0, pour une raison simple : sinon on valide tous les menus à la suite, et on passe de l'un à l'autre en un éclair (vous pouvez essayer, pour voir cheeky). Grâce à cette technique, le joueur sera obligé de lâcher le bouton et de réappuyer s'il veut valider une seconde fois.

 

 

      Des zombies plus intelligents !

   Oui, oui, je sais, c'est pas commun pour un zombie ! Mais heureusement, ça va être plus facile à programmer que de dresser de vrais zombies (si, si cheeky) !

   Tout va se passer ici dans la fonction checkFall() du fichier monster.c, et en fait, il va nous suffire de rajouter 3 fois rien, comme vous allez le voir ! cool

   Changez simplement ces deux lignes-là :

 

Fichier : monster.c

        //On teste si la tile sous le monstre est traversable (du vide quoi...).
        //Si c'est le cas, on renvoie 1, sinon 0.
        if (map.tile[y + 1][x] < BLANK_TILE - 20)
    

    Et :

	if (map.tile[y + 1][x] < BLANK_TILE - 20)
            return 1;
    

 

    Et voilà la fonction complète :

 

int checkFall(GameObject monster)
{
    int x, y;

    //Fonction qui teste s'il y a du sol sous un monstre
    //Retourne 1 s'il doit tomber, 0 sinon

    //On teste la direction, pour savoir si on doit prendre en compte x ou x + w (cf. schéma)
    if (monster.direction == LEFT)
    {
        //On va à gauche : on calcule là où devrait se trouver le monstre après déplacement.
        //S'il sort de la map, on met à jour x et y pour éviter de sortir de notre tableau
        //(source d'erreur possible qui peut planter notre jeu...).
        x = (int)(monster.x + monster.dirX) / TILE_SIZE;
        y = (int)(monster.y + monster.h - 1) /  TILE_SIZE;
        if (y < 0)
            y = 1;
        if (y > MAX_MAP_Y)
            y = MAX_MAP_Y;
        if (x < 0)
            x = 1;
        if (x > MAX_MAP_X)
            x = MAX_MAP_X;

        //On teste si la tile sous le monstre est traversable (du vide quoi...).
        //Si c'est le cas, on renvoie 1, sinon 0.
        if (map.tile[y + 1][x] < BLANK_TILE - 20)
            return 1;

        else
            return 0;
    }
    else
    {
        //Même chose quand on va à droite
        x = (int)(monster.x + monster.w + monster.dirX) / TILE_SIZE;
        y = (int)(monster.y + monster.h - 1) / TILE_SIZE;
        if (y < = 0)
            y = 1;
        if (y > = MAX_MAP_Y)
            y = MAX_MAP_Y - 1;
        if (x < = 0)
            x = 1;
        if (x > = MAX_MAP_X)
            x = MAX_MAP_X - 1;

        if (map.tile[y + 1][x] < BLANK_TILE - 20)
            return 1;

        else
            return 0;
    }
}


 

   En fait, il suffit de retrancher 20 à la valeur de BLANK_TILE, qui vaut 89, soit le numéro de la première tile solide. Ainsi, on va englober toutes les tiles plateformes dans les tiles solides, et nos monstres pourront marcher dessus, tout simplement ! wink

 

Attention : Là encore, pour éviter un problème avec le surligneur syntaxique Geshi, j'ai dû séparer les chevrons >= et <= par un espace. N'oubliez pas de les supprimer, si vous faites du copier/coller. 

 

   Eh voilà pour ce nouveau chapitre qui nous permet une fois encore de peaufiner notre jeu !

   Comme vous pouvez le voir, ce qui différencie un bon jeu d'un autre, c'est avant tout le souci du détail, pour simplifier au maximum la vie du joueur et donner l'apparence d'un jeu fini, qui ne laisse rien au hasard. cool

 

   Sur ce, je vous dis @ bientôt sur Meruvia ! smiley

 

 

 

Connexion

CoalaWeb Traffic

Today139
Yesterday238
This week1062
This month540
Total1745439

3/05/24