Au sanglier codeur

Un système d'animation par sprites

Introduction

Ce chapitre va vous expliquer comment réaliser un "lecteur" de grilles de sprites.

En commençant par expliquer le quoi, puis le pourquoi et enfin le comment. :)

Théorie

Première chose à savoir : qu'est-ce qu'un sprite ?

En effet pour une personne non habituée aux jeux en 2 dimensions, ce mot ne signifie peut être rien.

Voici la définition qu'en donne Wikipedia :
"Un sprite (en français lutin) est un élément graphique qui peut se déplacer sur l'écran.
En principe, un sprite est en partie transparent, et il peut être animé (c’est-à-dire qu'il est formé de plusieurs bitmaps qui s'affichent les uns après les autres)."

Voici donc une grille de sprites :

Une grille de sprites.

Vous l'aurez compris, le but de la manoeuvre est d'afficher successivement les images pour donner l'illusion du mouvement.

En général (et c'est la convention que nous allons adopter pour le code de notre classe) une ligne de la grille correspond à une animation.

Pratique - interface

Maintenant que nous avons compris quels sont les principaux objectifs de cette classe, définir l'interface sera un jeu d'enfant.

Premièrement, le constructeur : il doit prendre une std::string en paramètre qui va indiquer le path du fichier contenant la grille. Mais pas seulement !

Il faut aussi spécifier le nombre d'animations dans la grille (donc le nombre de lignes) ainsi que le nombre d'images par lignes (donc le nombre de colonnes).
Tant qu'on y est, on va aussi passer la position de la surface (donc un paramètre pour X et un pour Y).

Et enfin, le dernier paramètre va servir à spécifier la durée entre 2 changements de sprites durant l'animation.
Plus cette durée sera courte et plus l'animation sera jouée rapidement. A l'inverse, plus elle sera longue et plus l'animation sera jouée lentement.
Ce qui peut parfois nuire à sa qualité; si l'animation est jouée trop lentement, les raccord entre les frames seront peut être trop voyants.

CSpriteAnimation(const std::string &filename, Uint32 x = 0, Uint32 y = 0,
int nbColumns = 4, int nbLines = 4, unsigned int timeGap = 100);

Il nous faut une méthode qui permette de changer d'animation.
Par défaut, on bouclera sur la même animation indéfiniment, il faudra donc passer par cette méthode pour changer.

void setAnimation(int num);


Ensuite il nous faut une méthode pour pouvoir mettre en pause et une autre pour lancer l'animation.
Quel intérêt nous demanderez vous.
Et bien prenons le cas basique d'un petit (ou grand d'ailleurs ;) ) RPG 2D à base de sprites justement où on contrôle le personnage principal.
Les 3/4 du temps, les animations jouées seront celles de déplacement : gauche, droite...

Mais si l'animation choisie tourne en boucle, notre personnage fera des moulinets avec les jambes même à l'arrêt.
C'est pourquoi il ne faut déclencher l'animation que lorsqu'une touche de déplacement est enfoncée; et l'arrêter tout le reste du temps.

void stopAnimation();
void playAnimation();

Il est également possible que l'on ait besoin de démarrer à un certain endroit de l'animation ou que l'on doive sauter certaines frames.
Nous aurons donc besoin d'une méthode permettant de sélectionner la frame où démarrer dans l'animation.

void setFrame(int num = 0);

Pratique - implémentation

Les méthodes indiquant la pause et la lecture de l'animation sont les plus simple à implémenter.
Nous allons tout bêtement nous servir d'un booléen qui indiquera si l'animation doit être jouée ou pas.
Il suffira ensuite de le tester au début de la méthode mettant la surface à jour pour décider s'il faut changer quelque chose ou pas.

En ce qui concerne les méthodes de changement de frame et d'animation, pour comprendre comment elles fonctionnent il faut comprendre comment sont calculées et stockées la position et la taille de la surface à afficher.

Tout se joue dans le constructeur : on connais les dimensions totales de l'image car elle est contenu dans une SDL_Surface à laquelle on a accès.
Puis on connais le nombre de frames en largeur (nombre de colonnes) et le nombre de frames en hauteur (nombre de lignes) car ces 2 nombres sont passés en paramètres au constructeur (nbColumns et nbLines).
Ainsi, pour connaître la largeur d'une frame, on divise la largeur de la surface complète par le nombre de colonnes.
Et pour connaître la hauteur on divise la hauteur totale de la surface par le nombre de lignes.

On stocke ces 2 nombres dans les composantes h et w d'une variable de type SDL_Rect, ce qui nous laisse les composantes x et y de libres.

//m_sprite est une variable de type SDL_Rect
m_sprite.w = m_baseSurf->w / nbColumns;
m_sprite.h = m_baseSurf->h / nbLines;
m_sprite.x = 0;
m_sprite.y = 0;

Nous allons nous servir de ces 2 variables (m_sprite.x et m_sprite.y) pour stocker la position de l'origine de la frame à afficher.

Pour afficher une frame seulement et non l'intégralitée de la surface de l'image, nous allons nous servir du 2eme paramètre de SDL_BlitSurface qui permet justement de sélectionner une partie de la surface à blitté grâce à un SDL_Rect. :D

//&m_position représente la position de la surface par rapport à l'ecran.
//ecran est le nom de la surface sur laquelle on va blitté.
SDL_BlitSurface(m_baseSurf, &m_sprite, ecran, &m_position);

Ainsi, pour changer l'animation, il nous suffira d'augmenter la variable contenant la position en y de la frame de la hauteur d'une frame :

//m_anim est le numéro de l'animation à jouer.
m_sprite.y = m_anim * m_sprite.h;


De même pour changer le numéro de la frame :

//m_frame est le numéro de la frame à jouer.
m_sprite.x = m_frame * m_sprite.w;

Conclusion

Les animations par sprite sont très importantes car c'est le composant principal d'un jeu.
Hormis les images statiques, c'est ce que vous utiliserez le plus.
Il est donc important de bien en comprendre le principe, après quoi il est facile de l'implémenter.

N'hésitez pas à améliorer cette classe, ou à la recoder à votre sauce : elle est vraiment importante et il est préférable que vous la fassiez à votre idée pour que vous la compreniez bien.


Valid XHTML 1.0 Strict - Le Sanglier Codeur, par GuilOooo & Kevin Leonhart - Remonter en haut - Valid CSS !