Les collisions avec love2d

Disons que nous faisons un jeu où nous pouvons abattre des monstres. Un monstre devrait mourir quand il est touché par une balle donc, nous devons vérifier la condition suivante :
le monstre est-il entré en collision avec la balle ?

Nous allons créé une fonction qui vérifie les collisions. Pour ça, nous avons besoin de savoir quand 2 rectangles se percutent.

J’ai créé une image avec 3 exemples :

Représentation de plusieurs rectangles à des diverses dispositions pour comprendre les collisions
Représentation de plusieurs rectangles à des diverses dispositions pour comprendre les collisions

Il est temps de mettre en marche ce cerveau de programmeur si ce n’est pas déjà fait. Que ce passe-t-il dans le 3ème exemple qui ne se produit pas dans les 2 premiers ? “Il y a collision”

Oui, mais vous devez être plus précis. Nous avons besoin d’informations que l’ordinateur peut utiliser.

Regardez la positions des rectangles. Dans le 1er exemple, le rouge n’est pas en collision avec le bleu parce que le rouge est trop loin sur la gauche. Si le rouge était un peu plus prêt sur la droite, ils pourraient se toucher. Jusqu’où exactement ? Et bien si le côté droit du rouge est plus loin que le coté gauche du bleu. C’est vrai pour l’exemple 3.

Mais c’est aussi vrai pour l’exemple 2. Nous avons besoin de plus de conditions pour être sur qu’il y ait collision. L’exemple 2 nous montre que nous ne pouvons pas aller trop loin vers la droite. À quelle distance exactement ? De combien le rouge devrait se déplacer sur la gauche pour qu’il y ait collision ? Lorsque le côté gauche rouge est plus loin que le côté droit de bleu.

Donc nous avons 2 conditions. Est-ce suffisant pour s’assurer d’une collision ?

Hé bien non, regardez l’image suivante :

Représentation de 2 rectangles éloignés pour comprendre les collisions
Représentation de 2 rectangles éloignés pour comprendre les collisions

Cette situation concorde avec nos conditions. Le côté rouge est plus loin que le côté droit du bleu et le côté gauche du rouge est plus loin que le côté gauche du bleu. Pourtant, il n’y a pas collision. C’est parce que le rouge est trop haut. Il doit bouger vers le bas. Mais de combien ? Jusqu’à ce que le côté inférieur du rouge soit plus loin que le côté supérieur du bleu.

Mais si nous le bougeons trop loin, il n’y aura pas de collision non plus. Jusqu’où le rouge peut-il descendre pour qu’il y ai collision avec le bleu ? Tant que le coté supérieur du rouge est plus haut que le coté inférieur du bleu.

Nous avons maintenant 4 conditions. Sont-elles vraies pour ces 3 exemples ?

Représentation de plusieurs rectangles à des diverses dispositions pour comprendre les collisions
Représentation de plusieurs rectangles à des diverses dispositions pour comprendre les collisions

Le côté droit du rouge est plus loin que le côté gauche du bleu.

Le côté gauche du rouge est plus loin que le côté droit du bleu.

Le côté inférieur du rouge est plus loin que le côté supérieur du bleu.

Le côté supérieur du rouge est plus haut que le côté inférieur du bleu.

Oui, ils le sont !
Maintenant, nous devons transformer ces informations en une fonction.

D’abord, créons 2 rectangles :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function love.load()
  -- Création de 2 rectangles
  r1 = {
  x = 10,
  y = 100,
  width = 100,
  height = 100
  }

  r2 = {
  x = 250,
  y = 120,
  width = 150,
  height = 120
  }
end

function love.update(dt)
  -- Bougons un de ces rectangle
  r1.x = r1.x + 100 * dt
end

function love.draw()
  love.graphics.rectangle("line", r1.x, r1.y, r1.width, r1.height)
  love.graphics.rectangle("line", r2.x, r2.y, r2.width, r2.height)
end

Maintenant, nous créons une nouvelle fonction appelée checkCollision() avec les 2 rectangles comme paramètres :

1
2
3
function checkCollision(a, b)

end

D’abord, nous avons besoin des côtés des rectangles. Le côté gauche est la position x et le côté droit est la position x + la largeur. Même chose avec y et la hauteur :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function checkCollision(a, b)
  -- Avec les variables locales, il est d'usage d'utiliser les _ à la place du camelCasing
  local a_left = a.x
  local a_right = a.x + a.width
  local a_top = a.y
  local a_bottom = a.y + a.height

  local b_left = b.x
  local b_right = b.x + b.width
  local b_top = b.y
  local b_bottom = b.y + b.height
end

Maintenant, nous avons les 4 cotés de chaque rectangle. Nous pouvons les utiliser pour mettre nos conditions dans des if :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function checkCollision(a, b)
  -- Avec les variables locales, il est d'usage d'utiliser les _ à la place du camelCasing
  local a_left = a.x
  local a_right = a.x + a.width
  local a_top = a.y
  local a_bottom = a.y + a.height

  local b_left = b.x
  local b_right = b.x + b.width
  local b_top = b.y
  local b_bottom = b.y + b.height

  -- Si le côté droit du rouge est plus loin que le côté gauche du bleu
  if a_right > b_left and
  -- et si le côté gauche du rouge est plus loin que le côté droit du bleu
  a_left < b_right and
  -- et si le côté inférieur du rouge est plus loin que le côté supérieur du bleu
  a_bottom > b_top and
  -- et si le côté supérieur du rouge est plus haut que le côté inférieur du bleu
  a_top < b_bottom then
  -- Il y a collision!
  return true
  else
  -- Un de ces tests est faux donc il faut retourner false
  return false
  end
end

Bien, nous avons notre fonction. Essayons ! Nous dessinons les rectangles pleins ou délimités par des lignes :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function love.draw()
  -- Nous créons une variable locale appelée mode
  local mode
  if checkCollision(r1, r2) then
  -- Si nous avons une collision, dessinons les rectangles remplis
  mode = "fill"
  else
  -- autrement dessinons les rectangles comme des lignes
  mode = "line"
  end

  -- Utilisons la variable mode comme premier argument
  love.graphics.rectangle(mode, r1.x, r1.y, r1.width, r1.height)
  love.graphics.rectangle(mode, r2.x, r2.y, r2.width, r2.height)
end

Ça marche !
Maintenant, vous savez comment détecter la collision entre 2 rectangles.

Résumé

La collision entre 2 rectangles peut être vérifié avec 4 conditions

A et B sont 2 rectangles et il y a collision quand les 4 conditions suivantes sont vérifiées :

  • Le côté droit du A est plus loin que le côté gauche du B
  • Le côté gauche du A est plus loin que le côté droit du B
  • Le côté inférieur du A est plus loin que le côté supérieur du B
  • Le côté supérieur du A est plus haut que le côté inférieur du B