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.

 

 
 

 

  

 

Chapitre 31

Conversion du Big Tuto et des projets issus du Big Tuto de la SDL 1.2 vers la SDL 2 ! 

Tutoriel présenté par : Robert Gillard (Gondulzak)
Publication : 15 février 2014
Dernière mise à jour : 31 octobre 2015

      Préface de Jay

   Bonjour à tous, et merci d'avoir suivi ce Big Tuto jusqu'ici ! smiley

   Je sais que cela n'a sûrement pas été toujours facile (forcément, je fais aussi le SAV ! cheeky), mais vous avez tenu bon et je vous en félicite et remercie à la fois. Cependant, vous aurez sans doute remarqué que la SDL 1.2 a maintenant été dépassée par sa petite soeur : la SDL 2 qui vient de sortir et offre beaucoup plus de puissance graphique (même plus encore qu'avec glsdl). Et vous vous demandez sans doute comment convertir, à moindres frais de préférences, votre projet SDL 1.2.

   Et c'est là qu'intervient Gondulzak qui a fait le travail admirable de convertir tout ce Big Tuto en SDL 2 (les fichiers convertis sont à télécharger à la fin de chaque chapitre wink). Pour m'aider, il a également écrit ce 31ème chapitre qui reprend toutes les étapes par lesquelles il est passé pour effectuer cette conversion, et ce : chapitre par chapitre, problème après problème ! cool

   Normalement, vous devriez donc être à même de convertir rapidement votre projet de la SDL 1.2 vers la SDL 2, grâce à un guide qui vous aidera à venir à bout de toutes les erreurs de compilation que vous pourrez rencontrer.

   Pour ma part, j'ai commencé l'écriture d'un nouveau Big Tuto en SDL 2 : j'y reprendrai les bases de celui-ci mais en le complexifiant davantage pour un rendu plus professionnel, et il devrait aussi, à terme, proposer de nouveaux chapitres qui feront suite à ce 1er tuto : comme la programmation d'un boss, la gestion des joysticks, etc...

   Je continuerai aussi un peu ce tuto, une fois la conversion effectuée en SDL 2, pour rajouter les dernières pièces qui manquent (comme la gestion des joysticks quand même !) et j'en profiterai pour vous montrer comment optimiser 2-3 fonctions en SDL 2. wink

   Voilà, je vous laisse maintenant en compagnie de Gondulzak pour ce chapitre et à bientôt ! smiley

 

      Préliminaires

   Vous avez réalisé des projets à l'aide de la SDL 1.2 ou vous comptez vous lancer dans la réalisation d'un jeu sous cette plateforme ?

   Bravo ! cool Vous avez fait un excellent choix mais vous devez savoir que la SDL a évolué. En effet, celle-ci est passée de la version 1.2 à la version 2 et qu'elle utilise maintenant la puissance de la mémoire graphique.

   Alors, pourquoi s'en priver ? devil Un jour ou l'autre vous devrez sauter le pas et je vous propose de le faire de suite. C'est d'accord, vous êtes décidés ? wink Alors je vous propose dans un premier temps de relire les 4 premiers chapitres initiés par Jay pour le Big Tuto SDL 2

   Ceci dit, la SDL 2 est vaste et comporte un grand nombre de fonctions mais rassurez-vous. wink Pour pouvoir pleinement profiter de la puissance de l'accélération graphique proposée par la SDL 2, nous n'aurons besoin que d'un petit nombre limité de ces fonctions. Vous allez voir que modifier vos projets ou en créer un avec cette nouvelle plateforme n'a rien de compliqué et je vais vous aider à y parvenir. cool

   Sur ce sujet, mon expérience était nulle au départ et je ne connaissais de la SDL 2 que ce que tout un chacun en connaissait à l'époque, c'est à dire pas grand-chose. Cependant, ayant vite compris ce que l'on pouvait faire avec un minimum de fonctions, je décidai de me lancer dans la transformation en SDL 2 de tous les chapitres du Big Tuto SDL 1.2. Il s'agit de ceux-là même que Jay a écrits afin de vous apprendre à programmer votre propre jeu. Je vous invite d'ailleurs à télécharger tous les fichiers transformés que vous trouverez dans la section Téléchargements / Big Tuto SDL 1.2 – Jeu de plateformes - Conversion en SDL 2.

   Avant de vous expliquer la manière utilisée pour procéder à ces conversions ainsi que de discuter sur les problèmes rencontrés au cours de celles-ci, je vais vous montrer et vous expliquer le code d'un programme simple qui utilise les textures à l'aide de la mémoire graphique. J'ajouterai les différentes librairies annexes dans le code mais celles-ci ne seront pas utilisées lors de ce simple exemple. smiley

 

 

         1 – Un programme simple d'affichage d'une texture à l'écran

//Utilisation de la SDL 2 et des librairies annexes 
#include < sdl2/sdl.h >
#include < sdl2/sdl_image.h >
#include < sdl2/sdl_ttf.h >
#include < sdl2/sdl_mixer.h >
#include < stdio.h >
#include < string.h >

//Dimensions de la fenêtre
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;

///////////////////////
//Quelques fonctions //
//////////////////////

//Initialise la SDL ainsi que les différentes librairies
int init(char *title);

//Chargement des ressources
int loadResources();

//Libère les ressources et quitte la SDL
void cleanup();

//Charge une image et la transforme en texture
SDL_Texture* loadImage( char *name );

//La fenetre sue laquelle sera affiché le rendu graphique
SDL_Window* window = NULL;

//Le rendu de la fenêtre
SDL_Renderer* renderer = NULL;

//La texture à afficher
SDL_Texture* texture = NULL;
/* Avec la SDL 2.0 les textures possèdent leur propre type de données, SDL_Texture. 
   Si vous travaillez avec les textures vous aurez besoin d'un autre type de données dénommé
   SDL_Renderer afin de pouvoir effectuer le rendu sur l'écran. */


int init(char *title)
{
	// Initialise SDL Video 
	if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
	{
		printf ( "SDL n'a pu être initialisée ! SDL_ERROR : %s\n", SDL_GetError());
		exit(1);
	}
	
	//Création de la fenêtre
	window = SDL_CreateWindow(title,
		                          SDL_WINDOWPOS_CENTERED,
								  SDL_WINDOWPOS_CENTERED,
								  SCREEN_WIDTH, SCREEN_HEIGHT,
								  SDL_WINDOW_SHOWN);

	//Création d'un rendu graphique
	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);

    if (window == NULL || renderer == NULL)
        {
            printf("Impossible d'initialiser le mode écran à %d x %d: %s\n", SCREEN_WIDTH, 
				                                                     SCREEN_HEIGHT, SDL_GetError());
            exit(1);
        }

	//Initialisation du chargement des images png avec la SDL 2.0
	int imgFlags = IMG_INIT_PNG;
	if( !( IMG_Init( imgFlags ) & imgFlags ) )
	{
		printf( "SDL_image n'a pu être initialisée! SDL_image Error: %s\n", IMG_GetError() );
		exit(1);
	}

	// Cache le curseur de la souris 
	SDL_ShowCursor(SDL_DISABLE);

	/* Initialise SDL_TTF */
	if (TTF_Init() < 0)
	{
		printf("Impossible d'initialiser SDL TTF: %s\n", TTF_GetError());
		exit(1);
	}

	/* Chargement de la police */
	//font = loadFont("GenBasB.ttf", 32);  Inutile pour cet exemple

	//Initialise SDL_Mixer 
    int flags=MIX_INIT_MP3;
    int initted=Mix_Init(flags);
    if( (initted & flags) != flags)
    {
        printf("Mix_Init: Failed to init SDL_Mixer\n");
        printf("Mix_Init: %s\n", Mix_GetError());
        exit(1);
    }
}


//Une fonction qui charge les ressources diverses
int loadResources()
{
	//Chargement d'une texture PNG
	texture = loadImage( "Background22bis.png" );
	if( texture == NULL )
	{
		printf( "L'image n'a pû être chargée!\n" );
		exit(1);
	}

}


SDL_Texture *loadImage(char *name)
{
	/* Charge les images avec SDL Image dans une SDL_Surface */
	SDL_Surface *loadedImage = NULL;
	
	SDL_Texture *texture = NULL;
    loadedImage = IMG_Load(name);

	if (loadedImage != NULL)
	{
		// Conversion de l'image en texture
		texture = SDL_CreateTextureFromSurface(renderer, loadedImage);

		// On se débarrasse du pointeur vers une surface
		SDL_FreeSurface(loadedImage);
		loadedImage = NULL;
	}
	else
		printf("L'image n'a pas pu être chargée! SDL_Error :  %s\n", SDL_GetError());

		return texture;
}


//Fonction qui libère la mémoire et quitte SDL
void cleanup()
{
    // Libère la texture du background 
    if (texture != NULL)
    {
	SDL_DestroyTexture(texture);
	texture = NULL;
    }

    // Quitte SDL_Mixer
    Mix_CloseAudio();
    Mix_Quit();

    //On fait le ménage
    SDL_DestroyRenderer(renderer);
    renderer = NULL;
    SDL_DestroyWindow(window);
    window = NULL;

    // Fermeture des sous-systèmes
    IMG_Quit();
    TTF_Quit();
	
    //Quitte SDL
    SDL_Quit();
}


int main(int argc, char *argv[]) 
{
	//Initialise la SDL
	init("SDL 2.0 simple demo");
	 
	//Appel de la fonction loadResources()
	loadResources();
	
       //On entre dans la boucle de messages		
	SDL_Event event;
	bool quit = false;

      //Tant que l'utilisateur n'a pas quitté
      while( quit == false )
      {
         //Tant qu'il y a des évènements en cours
         if( SDL_PollEvent( &event ) )
         { 
            //Si l'utilisateur ferme la fenêtre
            if( event.type == SDL_QUIT )
            {
               //On quitte le programme
               quit = true;
            }
         }
			  
	  //On applique le rendu de la texture à l'écran
	  SDL_RenderCopy( renderer, texture, NULL, NULL );

	  //Mise à jour de l'écran
	  SDL_RenderPresent( renderer );
		    		
	}	
	    //Libère les ressources et ferme SDL
	    cleanup();
		return 0;	
}

 

 

Attention, pour éviter que le surligneur syntaxique (Geshi) ne prenne les chevrons pour des balises HTML, j'ai dû ajouter des espaces ! surprise N'oubliez pas de les enlever, si vous faites du copier/coller. wink Cela concerne exclusivement les quelques includes en début de code, comme par exemple : < sdl2/sdl.h > qui deviendra  <sdl2/sdl.h> après correction. Sinon, le plus simple reste de télécharger le projet complet en fin de chapitre. wink

   Ce programme comporte notre fonction main() et quelques autres fonctions que nous avons implémentées pour plus de lisibilité.

   Bien, voyons ce qui est nouveau dans ce programme par rapport à l'ancienne SDL 1.2. wink

    Intéressons-nous pour commencer à la fonction init(), celle qui initialise la SDL et les bibliothèques annexes. En paramètre à la fonction, nous passons un pointeur vers le titre de la fenêtre qui sera affiché dans la «barre caption» de celle-ci.

   L'initialisation vidéo se fait, comme avec la SDL 1.2, avec la fonction SDL_Init(). Les changements principaux arrivent par la suite :

   On s'aperçoit pour commencer de la disparition de la fonction SDL_SetVideoMode() et de certains de ses paramètres. Celle-ci est en effet remplacée par la fonction SDL_CreateWindow qui prend en paramètres :

- Un pointeur vers une variable qui affichera le titre de la fenêtre,
- SDL_WINDOWPOS_CENTERED : constante qui centrera la fenêtre sur l'écran (à noter qu'elle peut être remplacée par n'importe quelle valeur entière ou variable définissant l'endroit où doit être affichée la fenêtre sur l'écran). wink
- SCREEN_WIDTH et SCREEN_HEIGHT étant connus comme la largeur et la hauteur de la fenêtre,
- SDL_WINDOW_SHOWN est un nouveau paramètre de la SDL 2.0 qui indique d'une façon générale, quel système graphique sera utilisé pour représenter la fenêtre et son contenu (d'autres paramètres peuvent être utilisés, par exemple SDL_OPENGL pour un rendu OpenGL, mais SDL_WINDOW_SHOWN choisira de lui-même le système utilisé par la machine pour afficher le rendu).

   Voilà pour SDL_SetVideoMode(). Nous devons ensuite initialiser un rendu graphique, ceci se fait à l'aide de la fonction SDL_CreateRenderer() qui accepte comme paramètres : la fenêtre que nous venons de créer, une option générale pour le choix du rendu et la mise en oeuvre de la synchronisation verticale.

 

   Le chargement des images.png se fait par l'initialisation d'une série de flags (drapeaux) de la fonction IMG_INIT_PNG et qui renvoie IMG_GetError() si l'image n'a pu être initialisée (à noter que IMG_GetError() n'est autre qu'un « define » de la SDL 2.0 qui transforme SDL_GetError() en IMG_GetError() par une instruction interne #define IMG_GetError() SDL_GetError().

   Le curseur de la souris est ensuite caché / affiché à l'aide de l'instruction SDL_ShowCursor(SDL_DISABLE) / SDL_ShowCursor(SDL_ENABLE).

   La fenêtre et le rendu sont bien entendu initialisés avec un pointeur. Ces pointeurs, SDL_Window* et SDL_Renderer* sont déclarés dans la zone réservée à cet effet, ainsi que les autres variables globales et autres fonctions à déclarer.

   Comme nos images seront converties en textures (gérées par la mémoire graphique à la place de la mémoire RAM), nous initialisons également un pointeur vers ces textures, celui-ci étant déclaré SDL_Texture*.

   La suite de notre fonction Init() n'est qu'un exemple d'initialisations d'autres bibliothèques comme SDL2_ttf.lib ou SDL2_mixer.lib (A noter que TTF_GetError() suit le même raisonnement que celui utilisé plus haut pour IMG_GetError()).

 

   Voilà pour la fonction Init(), nous continuons avec la fonction LoadResources(). Cette fonction permet d'appeler loadImage() dont nous expliquons le contenu dans les lignes suivantes.

   Nous passons donc maintenant à la fonction loadImage(char *name). Cette fonction va charger des images (donc des textures) et c'est pourquoi son prototype est SDL_Texture *loadImage(char *name).

   Intéressons-nous à son contenu. Nous chargeons les images avec SDL_image dans une SDL_Surface. C'est le seul endroit où nous allons utiliser une SDL_Surface dans nos projets. Cette surface va ensuite être convertie en texture grâce à un pointeur de type SDL_Texture que nous initialisons à l'intérieur de la fonction et qui utilise la fonction SDL_CreateTextureFromSurface() à cet effet. A cette dernière, nous passons en paramètre notre pointeur vers le rendu graphique ainsi que l'image à transformer en texture. Pour terminer nous nous débarrassons du pointeur vers SDL_Surface et nous retournons la texture. Il s'agit d'une des façons les plus simples pour convertir une image en texture et je vous propose de garder ce schéma dans vos projets. wink

 

   La fonction cleanup (qui fait le ménage dans la mémoire et quitte la SDL) utilise maintenant des nouvelles fonctions de la SDL 2. En effet, ici, plus de SDL_FreeSurface(), à la place on utilise les fonctions SDL_DestroyTexture(), SDL_DestroyWindow() et SDL_DestroyRenderer(). Ces fonctions libèrent nos pointeurs que nous avons initialisés à NULL en début de programme. Les fonctions IMG_Quit(), TTF_Quit() et SDL_Quit() restent les mêmes que celles utilisées avec la SDL 1.2.

   Dans la fonction main() nous retiendrons simplement la fonction SDL_RenderCopy(), qui remplace l'ancienne SDL_BlitSurface et la fonction SDL_RenderPresent qui remplace SDL_Flip().

   Dans certains cas la fonction SDL_QueryTexture() est utilisée avant SDL_RenderCopy() mais nous verrons cela dans notre seconde partie, dans la discussion sur la transformation du Big Tuto SDL 1.2. wink

   Alors vous êtes convaincus qu'il n'y a rien de difficile à créer un programme avec la SDL 2 maintenant ? cool

 

              2 – Transformation du Big Tuto SDL (solutions et discussions)

   Bien, nous allons voir maintenant notre application spécifique qu'est le Big Tuto. Application spécifique certes, car construite avec une architecture recherchée qui permet une très grande visibilité et continuité au projet. Vous verrez par la suite que si vous avez déjà construit ou désirez construire vos projets en suivant cette architecture, vous n'aurez pas de difficulté à utiliser les fonctions SDL 2 permettant de profiter de l'accélération graphique. wink

   Nous ne parlerons ici que de quelques chapitres du Big Tuto, ceux qui ont une importance réelle sur les modifications à faire pour le passage à la SDL 2, les autres n'étant que des copier/coller des fonctions se rapportant aux chapitres qui les précèdent. cheeky

 

                  Chapitre 3

   Je m'explique. smiley Commençons par nous intéresser au premier chapitre qui affiche une fenêtre noire à l'écran, c'est à dire le chapitre 3. Nous voyons qu'il faut en premier lieu faire une modification dans le fichier defs.h et remplacer #include <SDL/SDL.h> par #include <SDL2/SDL.h> ( nous allons utiliser la SDL 2 maintenant wink).
   Nous avons vu dans l'exemple précédent que nous avions absolument besoin de trois pointeurs spéciaux dénommés SDL_Window*, SDL_Renderer* et SDL_Texture*. Dans ce chapitre, pas besoin d'initialiser un pointeur sur une texture, nous voulons simplement colorier une fenêtre. Les deux premiers pointeurs par contre sont nécessaires mais où les placer ? indecision

   Souvenez-vous de la structure Gestion du fichier structs.h du chapitre 3 du Big Tuto SDL 1.2. Celle-ci était construite comme suit : 

typedef struct Gestion
{
    SDL_Surface *screen;
} Gestion;

   Nous allons donc modifier le contenu de cette fonction et à la place, y ajouter nos pointeurs nécessaires pour la fenêtre et le rendu. wink Cette structure devient donc :

typedef struct Gestion
{
     SDL_Window *screen; //Remplace SDL_Surface en SDL2.0
     SDL_Renderer *renderer; //Pointeur qui va servir à initialiser l'accélération graphique
                             //de la SDL 2.0
} Gestion;

 

   Et c'est tout pour l'initialisation. Intéressons-nous à présent au fichier draw.c et à sa fonction draw(). Celle-ci nous intéresse particulièrement car elle va dessiner la fenêtre de couleur noire mais dans notre nouveau contexte.

void draw(void)
{
// Remplit le renderer de noir, efface l'écran et l'affiche.
SDL_SetRenderDrawColor(jeu.renderer, 0, 0, 0, 255); //RGBA (ici le noir)
SDL_RenderClear(jeu.renderer); // Efface l'écran
SDL_RenderPresent(jeu.renderer); // Remplace SDL_Flip() de la sdl 1.2
// Delai
SDL_Delay(1);
}

 

   Nous y voyons une fonction que nous n'avons pas rencontrée dans notre premier exemple: SDL_SetRenderDrawColor() qui permet de colorier une fenêtre. La fonction SDL_RenderClear() permet, quant à elle, d'effacer l'écran et nous avons vu que SDL_RenderPresent() remplaçait SDL_Flip() de l'ancienne SDL.

   Et c'est tout! cheeky Nous avons vu comment initialiser un projet dans notre premier exemple, les fichiers input.c et main.c ne présentant, quant à eux, aucune difficulté. Ce chapitre, ainsi que le chapitre 4 suivant, bien que faciles d'apparence sont la base même de tout ce qui sera nécessaire pour une transformation complète du projet et ne sont donc pas à dédaigner !

 

                  Chapitre 4

   Le chapitre 4 présente quant à lui une nouveauté, l'affichage d'une texture. Dans ce chapitre, nous allons charger une image qui sera transformée en texture et la première chose à faire est bien entendu d'ajouter #include <SDL2/SDL_image.h> dans le fichier defs.h.

   A partir de cet instant vous pouvez remplacer toutes les SDL_Image() par SDL_Texture() chaque fois que vous rencontrerez SDL_Image() dans vos fichiers de définitions.

 

   Intéressons-nous maintenant au fichier le plus important, le fichier Draw.c. Dans la fonction drawImage() nous devons passer un pointeur en paramètre vers une texture. A l'intérieur de cette fonction, nous nous apercevons alors que les lignes dest.w = texture->w; et dest.h = texture->h; provoquent une erreur de compilation :

Error : pointeur vers un type classe incomplète non autorisé

   Comment contourner cette erreur ? crying (n'oublions pas qu'à ce moment de la conversion j'étais en pleine découverte de la nouvelle version... angel )

   Nous savons que d'une part que SDL_Rect possède les variables x, y, w, et h dans sa structure. D'autre part, l'instruction suivant ces quatre affectations, SDL_QueryTexture() qui a pour but d'étendre la texture sur une surface définie, connaît implicitement les adresses &dest.w et &dest.h. Nous pouvons donc, afin de supprimer cette erreur de compilation sans affecter le bon déroulement du programme, nous défaire de ces deux lignes qui causent problème. Nous supprimons donc les deux lignes suivantes :

dest.w = texture->w;
dest.h = texture->h;

   Et la ligne suivante remplace bien entendu SDL_BlitSurface par SDL_RenderCopy().

   Dans la fonction Draw(), nous remplaçons SDL_Flip() par SDL_RenderPresent() et la fonction loadImage() ne présente plus de difficultés, nous avons vu son implémentation dans la première partie de ce tutoriel.

 

                  Chapitres 5 à 8

Chapitre 5 et 6 : Remplacez simplement les SDL_Surface par SDL_Texture.
Chapitre 7 : Level Editor. Pas de difficulté pour ce chapitre.
Chapitre 8 : Pas de difficulté pour ce chapitre.

 

                  Chapitre 9 : Animons le héros 

   Ici nous nous heurtons à un problème important. En effet, après avoir fait nos modifications habituelles, nous rencontrons la fonction drawanimatedplayer() du fichier animation.c et là, les lignes... 

if(player.frameNumber >= player.sprite->w / PLAYER_WIDTH - 1)
player.frameNumber = 0;

    ...nous amènent encore une belle erreur de compilation et cette fois il faut chercher et trouver ! devil

     1- utilisation du type non défini 'SDL_Texture'
     2- voir la déclaration de 'SDL_Texture'
     3- la partie gauche de '->w' doit pointer vers un type class/struct/union/générique

   player.sprite ->w est de nouveau la cause de notre problème mais nous nous apercevons que player.sprite ->w représente la longueur de notre feuille de sprites qui régit notre animation et que celle-ci est longue de 480 pixels. Donc... indecision
   Nous allons définir une nouvelle constante dans le fichier defs.h et c'est ainsi que nous ajoutons la ligne suivante dans ce même fichier yes : 

const int SPRITESHEET_LENGHT = 480; 

 

   Et maintenant nous pouvons remplacer notre ligne du fichier drawanimatedplayer() par celle-ci : 

if(player.frameNumber >= SPRITESHEET_LENGHT/ PLAYER_WIDTH - 1)
player.frameNumber = 0;

   Voilà, pas de problème pour le reste des fichiers du chapitre, on compile et on regarde notre lapin-ninja s'animer. wink

Note de Jay : Après avoir cherché un peu plus avant dans la doc de la SDL, j'ai trouvé la solution pour remplacer le code SDL 1.2 par son équivalent en SDL 2. Il suffit en fait de créer une variable w (pour width, vous pouvez aussi en rajouter une pour h / heigth, si besoin) et d'appeler SDL_QueryTexture(entity->sprite, NULL, NULL, &w, &h); pour retrouver les dimensions de notre texture. wink Voilà le code en question :

                int w;
                SDL_QueryTexture(entity->sprite, NULL, NULL, &w, NULL);
                
if(entity->frameNumber >= w / entity->w)
                            entity->frameNumber = 0;

 

                 Chapitres 10 et 11

Chapitre 10 : Mêmes problèmes et mêmes remarques que pour le chapitre 9.

Chapitre 11 : Gestion des collisions avec la map et les sauts - Pas de problème pour ce chapitre, il faut simplement suivre les recommandations des chapitres 5 à 8.

 

                 Chapitre 12

   Chapitre 12 : Ajouter 2 nouvelles animations et gérer le double-saut.

   Ici nous avons un réel problème... sad En effet, en plus de l'animation de notre héros dont nous connaissions la longueur de la feuille (480 px), nous devons maintenant gérer deux nouvelles animations de longueurs différentes (Idle left/right de 360 px et Jump left/right de 160 px). angry

   Comme vous le voyez, il n'est plus question d'utiliser la constante SPRITESHEET_LENGHT = 480 que nous avions introduite au chapitre 9. Alors que faire ...? crying

 

   J'ai retenu cette solution :

   Nous savons que nos animations sont affichées à partir de feuilles de sprites de longueur différentes certes, mais surtout, avec un nombre de frames différents. Vous voyez où je veux en venir ? wink

   Eh bien voilà, la solution qui me vient à l'esprit est de me baser uniquement sur le nombre de frames/feuille. Mais comment faire ? devil

   Nous allons introduire une nouvelle variable que nous appellerons maxFrameNumber. Celle-ci va nous permettre de connaître le nombre de frames d'une feuille chaque fois que nous mettrons en œuvre une animation. Et où allons-nous déclarer cette variable ? indecision Mais dans la structure Hero du fichier structs.h bien entendu, et ce, dans la zone des variables utiles pour la gestion de l'animation. wink

   Donc, dans notre structure hero, nous allons ajouter la variable maxFrameNumber afin d'obtenir la ligne suivante : 

int frameNumber, frameTimer, maxFrameNumber;

 

   Et n'oubliez pas de supprimer la ligne const int SPRITESHEET_LENGHT = 480; de notre fichier defs.h, celle-ci n'étant plus nécessaire. smiley

   Donc chaque fois que nous ferons appel à une image représentant une animation, il nous suffira de donner son nombre de frames à la variable maxFrameNumber et ceci va nous enlever cette épine qui était profondément plantée dans notre pied... devil

   Dans la fonction initializePlayer() du fichier player.c, nous ajoutons...

player.maxFrameNumber = 12; // 12 frames pour cette feuille de sprites

   ...à la suite de l'instruction player.etat = IDLE; puisque nous devons connaître l'état d'une animation pour indiquer son nombre de frames. wink

 

   Faites la même chose dans la fonction updatePlayer() :

   En dessous des lignes player.etat = WALK_LEFT; et player.etat = WALK_RIGHT; ajoutez simplement player.maxFrameNumber = 12; puisqu'il s'agit du nombre de frames de ces animations.
   Enfin n'oubliez pas l'état player.etat = IDLE; à la suite duquel vous ajouterez la ligne: player.maxFrameNumber = 9; ainsi qu'en dessous des lignes player.etat = JUMP_RIGHT; et player.etat = JUMP_LEFT; où vous ajouterez la ligne player.maxFrameNumber = 4;

   Il ne nous reste plus qu'à modifier notre fonction drawanimatedPlayer() du fichier animation.c et, dans celle-ci, vous remplacerez les lignes :

if(player.frameNumber >= SPRITESHEET_LENGHT/ PLAYER_WIDTH - 1)
player.frameNumber = 0;

 

   par celles-ci :

if(player.frameNumber >= player.maxFrameNumber - 1)
player.frameNumber = 0;

 

                 Chapitre 13

   Ce chapitre nous fait découvrir un nouveau fichier, le fichier monster.c. Ce fichier et les suivants nous proposeront donc des animations différentes et, à l'instar du chapitre précédent nous allons devoir modifier le code en rapport avec l'animation. J'aurais pu simplement le signaler et économiser de nombreuses lignes de texte mais j'ai jugé que pour cet exemple aussi, je devais vous donner des explications précises sur le sujet. smiley

   Notre fonction drawanimatedPlayer() est devenue la fonction drawAnimatedEntity() et gère maintenant une structure GameObject qui représente tant Player que Monster. Nous n'avons donc plus rien à modifier dans cette fonction.

   Nos modifications vont donc se porter sur le fichier monster.c en commençant par la fonction initalizeMonster(). Ici aussi nous devons connaître le nombre de frames utilisées par l'animation et comme première ligne de la fonction, avant d'entrer dans la boucle, nous ajoutons la ligne suivante :

monster[jeu.nombreMonstres].maxFrameNumber = 2;

Il est bien entendu inutile de le faire 50 fois à l'intérieur de la boucle, nous pouvons l'écrire une seule fois avant l'appel à loadImage("monster1.png")wink

   Voilà, c'est tout pour ce chapitre, mais n'oubliez pas la modification du fichier player.c ni nos précédentes modifications. smiley

   Il n'y a rien de spécial à ajouter sur les chapitres 14 à 25 sinon de ne pas oublier les recommandations des chapitres précédents.

 

                 Chapitre 26 : Ajoutons des boules de feu

   Ce chapitre nous oblige à procéder à quelques nouvelles modifications. En effet, si vous jetez un coup d’œil à la fonction createFireBall() du fichier fireballs.c, vous verrez les deux lignes suivantes qui nous donneront de nouveau une belle erreur à la compilation :

shuriken[jeu.nombreFireballs].w = jeu.Shuriken_image->w;
shuriken[jeu.nombreFireballs].h = jeu.Shuriken_image->h;

 

   Comme nous savons que notre image shuriken a des dimensions de 32 x 32 pixels nous allons donc déclarer deux nouvelles constantes dans le fichier defs.h. Et à l'intérieur de celui-ci nous ajouterons les lignes suivantes : 

//Dimensions shuriken
#define SHURIKEN_LENGHT 32
#define SHURIKEN_HEIGHT 32

 

   Ensuite, retournant dans notre fichier createFireBall(), nous remplacerons les deux lignes qui nous causaient un problème par celles-ci :

shuriken[jeu.nombreFireballs].w = SHURIKEN_LENGHT;
shuriken[jeu.nombreFireballs].h = SHURIKEN_HEIGHT;

 

   Voilà pour ce chapitre, ce n'était qu'une petite modification mais il fallait la faire pour nous permettre de compiler notre projet sans erreur. wink

   Le chapitre 27 qui ajoute les checkpoints ne cause aucune difficulté. smiley

 

                 Chapitre 28 : Des plateformes volantes

   Nous retrouvons ici le même problème que pour le chapitre 26. Dans la fonction initPlateforme() du fichier plateformes.c, nous voyons que les deux lignes suivantes nous causent la même erreur :

plateforme[jeu.nombrePlateformes].w = jeu.plateforme->w;
plateforme[jeu.nombrePlateformes].h = jeu.plateforme->h;

 

   Mais nous connaissons également les dimensions d'une plateforme qui sont de 96 x 20 pixels. wink
   De nouveau nous ajoutons deux nouvelles constantes dans le fichier defs.h :

#define PLATFORM_LENGHT 96
#define PLATFORM_HEIGHT 20

 

    Ensuite, retournant dans notre fichier initPlateforme(), nous remplacerons ces deux lignes qui nous causaient un problème par celles-ci :

plateforme[jeu.nombrePlateformes].w = PLATFORM_LENGHT;
plateforme[jeu.nombrePlateformes].h = PLATFORM_HEIGHT;

 

  Et c'est tout pour ce chapitre. wink

   Le chapitre 29 ne pose pas de problème lors de la conversion mais il s'agit de rester très concentré, car il est assez long. devil

   Quant au chapitre 30, vous n'en aurez bien entendu pas besoin, puisque vous voilà désormais passé en SDL 2 ! cool


   Voilà, j'espère que ce tutoriel vous aura été d'une certaine utilité et je vous souhaite un bon travail pour créer / modifier des projets avec cette nouvelle SDL. Quoi qu'il en soit, prenez la peine de télécharger les fichiers sur le site et lisez-en les commentaires, cela ne pourra qu'être un plus pour votre apprentissage de la SDL 2.0.  wink

    @ bientôt pour de nouveaux tutos ! smiley

 

 

 

 

Connexion

CoalaWeb Traffic

Today257
Yesterday178
This week757
This month4431
Total1743638

25/04/24