Latest article: Exporter des données depuis Excel

Comment ça marche : un jeu de combat

Tour d’horizon du fonctionnement d’un jeu de combat 2D, de l’animation à l’IA en passant par la physique et les collisions.

J’entretiens une relation étrange avec les jeux de combat : d’un côté ils me fascinent, et de l’autre je suis incapable d’y jouer correctement.

Même si je me débrouille bien dans Smash Bros et Soul Calibur, je suis quand même incapable de battre Bison dans Street Fighter II et les raccourcis vers les combos sur le stick droit de la manette est la seule raison pour laquelle j’arrive à avancer dans BlazBlue. Et si je joue contre quelqu’un qui s’investit vraiment dans le jeu, je me fais systématiquement massacrer 🙂

Mais cela ne m’empêche pas d’être émerveillé par de tels jeux. Je pense que ça vient en partie du fait que l’on dispose d’une large gamme de personnages, tous uniques. Aussi bien sur leur backstory, que leur design ou leurs coups. Et si un type de jeu me fascine, vous pouvez être sûr que je vais essayer d’en faire un, ou au moins de comprendre comment ça marche.

J’ai donc réalisé une petite démo de jeu de combat, une sorte de prototype avec peu de fonctionnalités, pour voir un peu les dessous de la chose. Et voici mon parcours.

Contrôles et physique

J’ai décidé pour ce prototype d’inclure les actions suivantes :

  • Se déplacer (courir)
  • Sauter
  • Se baisser
  • Attaque horizontale
  • Garde

J’ai changé le repère en mettant le zéro sur Y au niveau du sol et en inversant l’axe, ainsi sauter augmente la composante Y, et il n’est pas possible de descendre sous 0 (le sol).

J’ai ensuite une fonction qui transforme une telle coordonnée monde en coordonnée écran, pour afficher les sprites au bon endroit.

La physique est gérée avec deux vecteurs 2D : la position et la vélocité du combattant.

Pour déplacer le personnage, j’ai juste à modifier sa vélocité. Courir reviens à changer la vélocité sur X (300 et -300 actuellement) et pour s’arrêter il suffit de la remettre à zéro. De même, sauter revient à définir la vélocité sur Y (800, il faut que ce soit assez “fort” pour dépasser la gravité).

Link s'accroupit et Marth se protège

A chaque mise à jour de la simulation physique, j’ajoute à la position le produit entre la vélocité et le temps écoulé depuis la dernière frame (le delta time, en secondes) et réduit légèrement la vélocité avec la “décélération” qui augmente au fur et à mesure que le temps passe. Cela permet d’annuler la vélocité de façon fluide, ça fonctionne un peu comme la friction de l’air.

De même j’applique la gravité qui se fait de plus en plus forte, comme à la décélération. Lorsque le personnage touche le sol, je cesse d’appliquer la gravité et je remet les forces de décélération et de gravité à leur valeur d’origine.

Il est important de préciser que je traite les deux axes séparément, c’est bien plus simple comme ça.

Animations #1

Ma première implémentation du système d’animation est simple et se base sur des sprite sheets. Elle est en réalité tellement simple que je n’avais qu’une seule frame par animation.

(Les sprites viennent de The Spriters Resource et le fond de BlazBlue)

Une animation est composée d’une ou plusieurs frames, et le personnage ne peut avoir qu’une seule animation courante. Par défaut c’est “Idle” : le personnage se tient debout, sans bouger. Puis chaque action a sa propre animation, qu’elle soit déclenchée par l’appuie d’une touche (le saut, courir, etc), par la physique (retomber) ou par un évènement (se faire blesser).

En fonction de l’animation courante, les actions possibles changent. Par exemple il n’est pas possible de s’accroupir en même temps que l’on saute, et quand on est touché, on ne peut rien faire.

Marth en plein saut

Hitboxes

Chaque frame d’une animation a une liste de hitboxes, qui ne sont en réalité que des rectangles. Ces hitboxes sont divisées en 3 catégories :

  • Les bleus sont capables de prendre des dégâts
  • Les rouges infligent des dégâts si elles touchent une bleu
  • Les vertes bloquent les attaques

Si une frame n’a pas de hitbox, elle ne peut rien faire. C’est le cas par exemple des frames lorsqu’un ennemi est touché, il est invulnérable pendant un certain temps.

Après avoir pris une attaque, Marth est invulnérable pendant un court instant

Les collisions sont testées entre les différentes hitboxes et soustraire la position du joueur à celle de l’ennemi permet d’obtenir le vecteur direction de l’attaque afin de propulser la cible dans la bonne direction. J’imagine que spécifier ce vecteur à la main pour chaque attaque est une meilleure idée, cela permettrait plus de souplesse (on choisit la direction où on veut que l’adversaire soit éjecté), mais pour l’exemple courant cela suffit.

Intelligence artificielle

L’IA fonctionne comme une simple machine à états, tellement simple qu’elle est réalisée avec une série de if/else.

En fait elle est aussi simple qu’inefficace : l’ennemi se rapproche du joueur jusqu’à être à sa portée, et décide alors de réaliser une action au hasard entre attaquer, sauter, se baisser et se défendre. Vraiment, qui espère gagner un combat comme ça ?

Je n’ai pas encore eu le temps de vraiment me pencher sur cette partie là, donc pour le moment ça restera comme ça.

Toutefois je pense qu’une machine à état devrait être suffisant pour faire une bonne IA, à condition qu’elle soit bien pensée et assez complète bien sûr.

Animations #2

L’inconvénient des sprite sheets, c’est que ça demande beaucoup de boulot, et beaucoup de mémoire. Et si vous augmentez la résolution, ce qui devient une nécessité avec les écrans d’ajourd’hui, vous augmentez le temps nécessaire pour créer chaque frame ainsi que le poids de chaque image.

Une autre solution, est d’emprunter une technique du monde de la 3D : l’animation squelettale.

On commence par découper notre personnage en plusieurs parties :

Puis on les rassembles et les animes, comme on le ferait avec un système d’animation 3D à base des bones.

Bien réalisée, l’animation squelettale peut être complétement transparente et bluffante.

Les jeux Vanillaware en sont l'exemple parfait

Mal réalisée, cela donne un effet “marionnette” complètement ridicule. Bon malheureusement, ce que je vais vous montrer à l’instant tombe dans cette catégorie.

Pour être bien réalisé, il faut :

  • Bien sûr, permettre la rotation de chaque bone (c’est la base)
  • Permettre également la translation
  • Ainsi que la la mise à l’échelle
  • Et enfin permettre le changement d’image associée à chaque bone

Ensuite avec de la patience, du temps et des compétences on peut arriver à l’exemple ci-dessus.

Voici une capture d’écran de mon éditeur d’animation :

Cliquez pour voir en grand

Sur la gauche, on a la liste des “parts”, il s’agit d’une image qui se comporte comme un bones.

En dessous, il y a un petit espace pour configurer la “part” sélectionnée, notamment le point d’origine du bone par rapport à l’origine de l’image, la position par rapport au bone parent (et le bone parent en question) et enfin l’ordre d’affichage (Z).

Sur la droite, c’est la liste des animations.

Comme il n’y a pas d’interpolation pour le moment, on peut changer la durée de chaque frame séparément. Ensuite il est possible de changer l’angle de rotation de chaque “part”.

Si vous faites attention, vous verrez derrière un autre sprite légèrement transparent, il est là pour l’onion skinning. Il s’agit de la frame précédente, affichée pour servir de repère.

Le personnage présenté est décalqué inspiré de Ragna, de BlazBlue.

Mentions

    Discussion

    1. Iliak

      March 2, 2011
      7:19 pm

      Salut,
      Article intéressant. Comme quoi avec des techniques toutes bêtes on peut faire des trucs sympas !
      Aurais tu des liens ou documents qui entrent plus en profondeur dans les détails ?
       
      Iliak

      Reply

      • Dri

        March 2, 2011
        8:29 pm

        Salut,

        Techniquement, les jeux de combats sont assez simple à réaliser, c’est artistiquement que ça se complique…

        Je n’ai pas de site en tête, mais http://shoryuken.com/ peut se révéler intéressant, il y a des détails frames par frames, ainsi que des hitboxes. Même si c’est très orienté gameplay on peut y apprendre pas mal de choses.

        Reply

    2. Kannagi

      June 15, 2011
      10:45 am

      Article intéressant surtout que je trouve peu d’article en français qui en parle.
      J’avais fait une démo aussi d’un jeu de combat , et je suis assez d’accord avec l’ensemble de ce qui a été dit ,en tous cas je serais bien curieux de testé ta démo ^^

      Reply

    3. areoarcher

      March 25, 2013
      6:06 pm

      c’est quoi le logiciel que ta utiliser pour faire le jeux video

      Reply

      • Dri

        March 25, 2013
        10:52 pm

        Visual Studio

        Reply

    Reply to Kannagi (cancel)