Des collisions dans un jeu 2D en 5 minutes chrono sur PICO-8

Des collisions dans un jeu 2D en 5 minutes chrono sur PICO-8

Ce sujet est un des plus compliqués quand on débute la création d’un jeu en 2D car si on utilise PICO-8, on va être obligé de refaire toutes les collisions “à la main”.

Ne vous inquiétez pas, la logique derrière les collisions est simplissime et à la fin de cette article, tout cela n’aura plus aucun secret pour vous !

La théorie des collisions 2D

L’objectif de la détection de collision que je vais prendre dans cet exemple est simple : on a un projectile A et un ennemi B et on veut savoir si la balle a touché l’ennemi.

Ils ont chacun une position dans l’espace ainsi qu’une largeur et une hauteur en pixel.

A partir de ces propriétés, on va devoir déterminer la boîte de collision pour chaque élément et ensuite vérifier si ces boîtes sont actuellement en collision ou non.

Pour déterminer une boîte de collision, on va définir les positions du coin haut gauche (X1,Y1) qui sont la position du sprite (X,Y) et du coin bas droit (X2,Y2) que l’on obtient en faisant (X+largeur,Y+hauteur).

Une fois que l’on a déterminé ces 4 positions (2 pour chaque objet), on va vérifier 4 conditions pour savoir si ils ne sont pas en collision.

Ça peut vous paraître étrange de prendre le problème à l’inverse mais c’est une manière optimisée de vérifier si deux éléments se superposent.

Les quatre conditions qui font que les deux objets ne sont pas en collision sont :

  • Est-ce que A.X1 est supérieur à B.X2 ? OU
  • Est-ce que A.Y1 est supérieur à B.Y2 ? OU
  • Est-ce que A.X2 est inférieur à B.X1 ? OU
  • Est-ce que A.Y2 est inférieur à B.Y1 ?

Regardez chaque condition avec le schéma du carré bleu et rouge, vous devrez rapidement comprendre pourquoi dans chacun de ces cas, la collision est impossible.

Il ne reste plus qu’à inverser le résultat et on sait si A et B sont en collision ou non.

La théorie est aussi simple que ça. Vous pouvez retrouver l’explication dans cette vidéo si vous avez encore quelques difficultés à comprendre le principe :

Comment faire des collisions sur PICO-8 ?

La théorie est acquise, maintenant nous allons passer à la pratique !

Ça va rester très logique et très simple, vous verrez que c’est assez plaisant quand ça fonctionne 😉

La première étape est de pouvoir déterminer la boîte de collision d’un objet. Comme sur PICO-8 les sprites font minimum du 8 par 8, on va devoir définir une “sous-boîte” de collision pour un sprite. Je m’explique…

Imaginons que le projectile ne soit qu’un petit carré de 2*2 pixels au centre du sprite, qui lui en fait 8*8, nos collisions ne vont pas être précises si on donne simplement la position (X,Y) et la largeur,hauteur de 8.

On va donc définir une boîte de collision (box) avec la position du pixel le plus haut à gauche à l’intérieur du sprite (x1,y1) et la position du pixel le plus bas à droite (x2,y2).

Pour le sprite que j’ai décrit au-dessus, on va donc avoir un objet qui ressemble à :

BULLET={
  S=1,   -- numéro du sprite
  X=30,  -- position X
  Y=30,  -- position Y
  BOX={X1=3,Y1=3,X2=4,Y2=4} -- boîte de collision à l'intérieur du sprite
}

La fonction pour définir la boîte de collision d’un sprite sera donc :

FUNCTION GET_COLLISION_BOX(O)
  RETURN {
    X1=O.X+O.BOX.X1,
    Y1=O.Y+O.BOX.Y1,
    X2=O.X+O.BOX.X2,
    Y2=O.Y+O.BOX.Y2
  }
END

Ensuite, pour vérifier la collision entre deux objets, on va récupérer ces deux boîtes de collision et vérifier les 4 conditions que je vous ai partagé plus haut.

FUNCTION CHECK_COLLISION(A,B)
  LOCAL BOXA = GET_COLLISION_BOX(A)
  LOCAL BOXB = GET_COLLISION_BOX(B)
  RETURN NOT (BOXA.X1 > BOXB.X2 OR
              BOXA.Y1 > BOXB.Y2 OR
              BOXA.X2 < BOXB.X1 OR
              BOXA.Y2 < BOXB.Y1)
END

ATTENTION : Les objets A et B doivent contenir les champs X, Y et BOX sinon le système ne fonctionnera pas !

Maintenant vous pouvez faire un petit programme comme celui-ci pour tester :

FUNCTION GET_COLLISION_BOX(O)
  RETURN {
    X1=O.X+O.BOX.X1,
    Y1=O.Y+O.BOX.Y1,
    X2=O.X+O.BOX.X2,
    Y2=O.Y+O.BOX.Y2
  }
END

FUNCTION CHECK_COLLISION(A,B)
  LOCAL BOXA = GET_COLLISION_BOX(A)
  LOCAL BOXB = GET_COLLISION_BOX(B)
  RETURN NOT (BOXA.X1 > BOXB.X2 OR
              BOXA.Y1 > BOXB.Y2 OR
              BOXA.X2 < BOXB.X1 OR
              BOXA.Y2 < BOXB.Y1)
END

FUNCTION _INIT()
  BULLET={
    S=1,X=30,Y=30,
    BOX={X1=3,Y1=3,X2=4,Y2=4}
  }
  MONSTER={
    S=2,X=50,Y=30,
    BOX={X1=0,Y1=0,X2=7,Y2=7}
  }
END

FUNCTION _DRAW()
  CLS()
  IF CHECK_COLLISION(BULLET,MONSTER) THEN
    CLS(8)
  END
  SPR(BULLET.S,BULLET.X,BULLET.Y)
  SPR(MONSTER.S,MONSTER.X,MONSTER.Y)
END

FUNCTION _UPDATE()
  MONSTER.X -= 1
  IF MONSTER.X < 0 then
   MONSTER.X = 50
  END
END

Vous avez désormais toutes les clés en main pour ajouter des collisions dans votre jeu sur PICO-8 !

Cliquez-ici pour recevoir mon guide pour débuter la programmation et la création de jeux vidéo sur PICO-8 !

RSS
Facebook
Facebook

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

Tu as aimé l'article? Partage le blog !