Sprites enrichis

Jusqu’à présent, nous avons considéré les sprites (petits objets animés) comme une simple image, ou un simple ensemble d’images. Cependant, rien n’interdit, en se faisant son propre éditeur de sprite, de pouvoir rajouter des informations directement dans les images pour aider au calcul de collision, ou même à l’affichage.

Ce sera donc le graphiste qui rajoutera des informations qui nous seront fort utiles.

Voyons ici quelques concepts d’informations qu’on pourrait rajouter aux images.

Point chaud et point d'action

Ici, nous allons parler du point chaud et du point d’action. Ce sont des concepts qui simplifient bien la vie dans certains cas. Le vieux logiciel de création Klick & Play utilisait ces concepts.

Le point chaud

Le point chaud ne concerne pas directement les collisions, mais il peut être utile d’en parler.

Regardons ensemble l’image suivante :

Dhalsim
Dhalsim

Vous avez reconnu ce cher Dhalsim, fakir combattant assez élastique dirons nous. Quand il donne un coup, il a une très grande portée ! Nous voyons ici deux images, l’une où Dhalsim ne donne pas de coup, et une où il donne un coup de pied bien tendu. En bleu, j’ai dessiné les boîtes englobantes, elles ne sont pas de la même largeur. Cela va poser problème.

Problème

Imaginons que vous vouliez faire une animation de Dhalsim qui donne un coup de pied. Vous avez ces deux images, ci-dessus, et vous voulez faire l’animation.

Vous blittez donc tour à tour chaque image, un blit colle l’image à la position x,y de telle sorte que le coin supérieur gauche de l’image blittée soit à la coordonnée (x,y).

Conséquence immédiate : vous aurez un Dhalsim qui va vivement partir à droite quand il donnera un coup de pied, parce que dans une image, sa tête est à coté du coin supérieur gauche, et dans l’autre, elle est loin. L’animation va être complètement ratée.

La seule solution est de blitter la première image à une position (x,y), et de blitter la seconde à une position (x2,y) avec x2 < x, et de bien calculer x2 de façon à ce que le corps de Dhalsim reste au même endroit.

C’est extrêmement contraignant, surtout s’il faut faire ça avec chaque image. Et pourtant, si on veut une belle animation, il faut calculer un x2 correct.

Insertion du point chaud

Pour palier ce problème, nous allons dire au graphiste que nous souhaitons des informations supplémentaires, et qu’il nous les donnera graphiquement.

Regardez les points rouges que j’ai mis au pied de Dhalsim dans chaque cas. Imaginez maintenant qu’on ait une fonction de blit qui affiche le personnage non pas en considérant que l’ancrage est en haut à gauche, mais qu’il est au niveau de ce point rouge. Autrement dit, le point rouge est à la coordonnée (x,y) du blit et Dhalsim se dessine autour.

Le problème est donc résolu : l’animation sera convenable.

Ce point rouge, c’est le point chaud. Il faudra définir un point chaud pour chaque image pour notre cas.

À vous de programmer un éditeur qui permet au graphiste de définir un point chaud pour chaque image à blitter.

Vous savez, il y a deux possibilités de gérer les sprites : soit un sprite par surface, soit une planche de sprite sur la même surface et un blit partiel. Dans le premier cas, chaque surface devra avoir un point chaud. Dans le deuxième, il y aura autant de points chauds que d’images dans la planche.

Un point chaud, c’est juste une coordonnée (x,y) locale à l’image. Dans la première image, on aura par exemple le point chaud qui a comme coordonnée (45,100), et dans la deuxième, il a comme coordonnée (167,100).

Ces coordonnées ne seront pas entrées à la main par le graphiste, mais en un clic : le graphiste a son image sur l’écran, il clique sur l’option « mettre point chaud » puis il clique sur son image entre les pieds de Dhalsim, et l’éditeur stocke la coordonnée de souris relative à l’image, tout simplement. Cela reste donc visuel. C’est la machine qui fait les calculs.

Notez qu’un point chaud à la coordonnée (0,0) est un point chaud en haut à gauche, donc ça nous ramène au cas du blit normal !

Blit sur le point chaud

Les librairies graphiques ne gèrent pas les points chauds. Elles fournissent une fonction Blit (SDL_BlitSurface par exemple) qui va blitter de tel sorte que le point (x,y) passé soit le coin supérieur gauche de l’image. Pour créer une fonction BlitAuPointChaud, il suffit de faire deux soustractions.

Soit une fonction :

void Blit(Image Source, Image Destination, int x, int y);

La fonction BlitAuPointChaud s’implémente ainsi :

void BlitAuPointChaud(Image Source, Image Destination, int x, int y, int xpointchaud, int ypointchaud)
{
    Blit(Source, Destination, x - xpointchaud, y - ypointchaud);
}

Pour les utilisateurs de SDL, nous aurons :

void BlitAuPointChaud(SDL_Surface * Source, SDL_Surface * Destination, int x, int y)
{
    SDL_Rect R;
    R.x = x - xpointchaud;
    R.y = y - ypointchaud;
    SDL_BlitSurface(source, NULL, destination, &R);
}

Sous AABB

La notion de sous AABB (ou Sub AABB, qu’on notera SAABB) va permettre des collisions plus fines, et pas tellement plus calculatoires. Cependant, tout comme les points chauds et points d’action, les informations de SAABB devront être fournies avec les sprites au programmeur, grâce à un éditeur créé pour l’occasion.

Définition

Regardons ensemble l’image suivante :

Ken de Street Fighters
Ken de Street Fighters

Nous voyons Ken dans plusieurs positions. Cependant, vous pouvez constater que j’ai rajouté des AABB autour de lui, dans chaque image. Ce sont les SAABB. J’en ai rajouté seulement quelques unes, mais qui permettent d’approximer la forme correctement.

Collision

Nous avons vu qu’un algorithme de collision dans ce cas là peut être simplement un algorithme de "Point dans AABB". Si nous considérons la AABB globale de l’image cible, vous restez trop approximatif dans notre cas : vous pouvez frapper l’air au dessus de l’épaule de Ken…

Pour un algorithme plus fin, on appellera plusieurs fois l’algorithme "Point dans AABB" dans chacune des SAABB. Si le point testé touche une seule SAABB, alors il y a collision.

Première optimisation

Si on veut tester la collision d’un point dans le personnage, avant de tester chaque SAABB, on testera d’abord la AABB entière, celle de l’image. Si on ne touche pas cette AABB, inutile d’aller plus loin : il n’y a pas collision. Sinon, on teste chacune des SAABB.

Deuxième optimisation

Nous pouvons considérer les SAABB en hiérarchie. Par exemple, vous voyez la première image, il y a plusieurs SAABB bleues côte à côte. Soit on les teste une par une, soit on teste d’abord la AABB de l’ensemble des boîtes bleues. Si on ne touche pas cette dernière, inutile de tester chacune des SAABB internes…

Davantage de sémantique

Vous savez, dans Street Fighter 2 ou autres jeux de combat, un personnage souffrira différemment si il prend un coup dans la tête, dans le corps, ou dans les jambes.

Regardez le dessin ci-dessus : j’ai fait exprès de dessiner en bleu les boîtes correspondant aux jambes, en jaune celle de la tête, en vert celle du torse, en violet celle des bras. Si le graphiste respecte bien un tel codage de SAABB, alors on pourra détecter, lors d’une collision, dans quelle couleur de SAABB tape le point d’action de l’autre joueur.

Cela nous permettra de savoir immédiatement si on a tapé dans la tête, dans le torse, les pieds…

C’est ce qu’on appelle rajouter de la sémantique directement au niveau des sprites.

Au lieu d’avoir une suite d’image sans données, on aura une banque de sprite, qui contiendra des images, mais aussi plein d’informations pour chaque image, informations qui auront été rentrées graphiquement à la souris avec un éditeur, et qui faciliteront énormément le travail des programmeurs.


Cette partie nécessite donc un travail en amont au niveau de la création des sprites pour être utilisable. N’oubliez pas que les boîtes de jeux se programment souvent leurs propres éditeurs, leurs propres outils, en fonction de leurs besoins.

L’idée est de donner graphiquement le maximum de sémantique au niveau des images elles mêmes, pour simplifier la tâche du programmeur par la suite.