Le debugging avec love2d

Un bug est quelque chose qui ne va pas dans un programme (ou dans notre cas notre jeu). Le débogage est l’art de corriger ces bogues afin qu’ils ne se reproduisent plus. En tant que programmeur, il est naturel de rencontrer de nombreux bugs, donc le débogage est une compétence très précieuse.

J’ai écrit un petit jeu.

 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
28
function love.load()
  circle = {x = 100, y = 100}
  bullets = {}
end

function love.update(dt)
  for i,v in ipairs(bullets) do
    v.x = v.x + 400 * dt
  end
end

function love.draw()
  love.graphics.circle("fill", circle.x, circle.y, 50)

  for i,v in ipairs(bullets) do
    love.graphics.circle("fill", v.x, v.y, 10)
  end
end

function love.keypressed()
  if key == "space" then
    shoot()
  end
end

function shoot()
  table.insert(bullets, {circle.x, circle.y})
end

Lorsque vous appuyez sur la touche espace, il tire une balle. Ou du moins c’est ce qui est censé se produire, mais cela ne fonctionne pas. Je ne vois aucune balle apparaître. Essayons de savoir pourquoi.

Voici quelques-unes des raisons pour lesquelles je peux penser pourquoi cela ne fonctionne pas.

  • Il ne tire pas les balles.
  • Il tire des balles, mais il ne les dessine pas correctement.
  • Il tire les balles, mais elles sont dans la mauvaise position.

Pour comprendre où cela va mal, nous pouvons utiliser print. Par exemple, utilisons print à l’intérieur de la boucle for dans love.update pour vérifier la position x du cercle parce que si les balles ne sont pas créer, l’affichage ne sera jamais fait.

1
2
3
4
5
6
function love.update(dt)
  for i,v in ipairs(bullets) do
    v.x = v.x + 400 * dt
    print(v.x)
  end
end

N’oubliez pas que vous pouvez ajouter le code suivant en haut de votre main.lua pour que la sortie apparaisse immédiatement sans avoir besoin de quitter le jeu

1
io.stdout:setvbuf("no")

Exécutez le jeu et appuyez sur la touche espace plusieurs fois pour tirer. Comme vous pouvez le voir, il n’y a aucun affichage dans votre console. On dirait que nous ne remplissons pas notre tableau de balles. Assurons-nous d’appeler réellement la méthode shoot en y mettant un print.

1
2
3
4
5
6
function shoot()
  table.insert(bullets, {circle.x, circle.y})

  -- Did you know that print takes infinite amount of arguments?
  print("How many bullets?", #bullets)
end

Essayez de tirer et vous verrez que nous ne voyons toujours rien d’affiché sur la console. Bizarre, parce que notre instruction if dit if key == « space », et nous appuyons définitivement sur espace. Mais pour être sûr, affichons la valeur de la clé. Et qui sait, peut-être que nous avons mal orthographié love.keypressed et qu’il n’atteint pas ce code du tout.

1
2
3
4
5
6
7
8
function love.keypressed()
  -- Adding texts like these gives context to your print.
  -- This is especially useful when you have multiple prints.
  print("What is the key?", key)
  if key == "space" then
    shoot()
  end
end

Lorsque vous essayez de tirer à nouveau, vous verrez que quelque chose est en cours d’affichage. Il semble que la valeur de la clé soit nulle. Comment est-ce possible, car LÖVE passe la touche comme premier argument. Mais attendez, nous n’avons pas de paramètre appelé touche (key). J’ai oublié de l’ajouter lors de la création de la fonction. Corrigeons cela.

1
2
3
4
5
6
function love.keypressed(key)
  print("What is the key?", key)
  if key == "space" then
    shoot()
  end
end

D’accord, maintenant, lorsque vous appuyez sur l’espace, il ne tire toujours pas, mais quelque chose d’autre se produit. Vous obtenez une erreur.


Lire et corriger les erreurs

Une erreur se produit lorsque le code tente d’exécuter quelque chose qui n’est pas possible. Par exemple, vous ne pouvez pas multiplier un nombre par une chaîne. Cela vous donnera une erreur

1
print(100 * "test")
Erreur d’arithmétique
Erreur d’arithmétique

Un autre exemple est d’essayer d’appeler une fonction qui n’existe pas.

1
doesNotExist()
Erreur avec une fonction qui n’existe pas
Erreur avec une fonction qui n’existe pas

Dans notre jeu de tir par balle, nous obtenons l’erreur suivante :

Tente de faire une opération arithmétique avec une variable à nil
Tente de faire une opération arithmétique avec une variable à nil

Alors, que nous dit exactement l’erreur ?
Parce qu’une erreur que beaucoup de débutants font est qu’ils ne réalisent pas que le message d’erreur vous dit exactement pourquoi et où l’erreur se produit.

1
main.lua:10:

Cela nous indique que l’erreur se produit sur la ligne 10 (cela peut être une ligne différente pour vous).

1
attempt to perform arithmetic on field 'x' (a nil value)

L’arithmétique signifie un calcul, par ex. en utilisant +, -, *, etc. Il a essayé de calculer en utilisant le champ x, mais x est une valeur nulle.

C’est donc bizarre, parce que nous donnons à la table une valeur x et y, non? Et bien non. Nous ajoutons les valeurs à la table, mais nous ne les attribuons pas à un champ. Corrigeons ça.

1
2
3
function shoot()
  table.insert(bullets, {x = circle.x, y = circle.y})
end

Et maintenant ça marche enfin. Nous pouvons tirer des balles !

Regardons un nouveau code où je crée une classe de cercle et dessinons-le plusieurs fois (vous n’avez pas nécessairement à écrire la totalité).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Object = require "classic"

Circle = Object:extend()

function Circle:new()
  self.x = 100
  self.y = 100
end

function Circle:draw(offset)
  love.graphics.circle("fill", self.x + offset, self.y, 25)
end

function love.load()
  circle = Circle()
end

function love.draw()
  circle:draw(10)
  circle:draw(70)
  circle.draw(140)
  circle:draw(210)
end

En exécutant cela, j’obtiens l’erreur suivante :

Tente d’indexer une propriété sur self
Tente d’indexer une propriété sur self

« Tenter d’indexer » signifie qu’il a essayé de trouver une propriété de quelque chose. Donc, dans ce cas, il a essayé de trouver la propriété x sur la variable self. Mais selon l’erreur, self est une valeur numérique, il ne peut donc pas le faire. Alors, comment est-ce arrivé? Nous utilisons deux points (:) pour notre fonction afin qu’elle ait automatiquement self comme premier paramètre, et nous appelons la fonction avec deux points pour qu’elle passe self comme premier argument. Mais quelque part, quelque chose a mal tourné. Pour savoir où cela s’est mal passé, nous pouvons utiliser le Traceback.

La partie inférieure de l’erreur nous indique le « chemin » qu’il a fallu avant d’atteindre l’erreur. Il est lu de bas en haut. Vous pouvez ignorer la ligne xpcall. La ligne suivante indique main.lua: 21: dans la fonction ‘draw’. Intéressant, jetons un coup d’œil. Ah oui, je vois. À la ligne 21, j’ai utilisé un point au lieu d’un deux-points (circle.draw (140)). Je l’ai changé en deux points et maintenant ça marche !

Syntax errors (Erreurs de syntaxe)

Une erreur de syntaxe se produit lorsque le jeu ne peut pas commencer, car quelque chose ne va pas avec le code. Il essaie de « lire » le code mais ne le comprend pas. Par exemple, rappelez-vous comment vous ne pouvez pas avoir un nom de variable commençant par un nombre ?

Lorsque vous essayez de le faire, cela vous donnera une erreur :

Erreur de syntaxe
Erreur de syntaxe

Jetez un oeil au code suivant (encore une fois, pas besoin de taper)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function love.load()
  timer = 0
  show = true
end

function love.update(dt)
  show = false
  timer = timer + dt

  if timer > 1 then
    if love.keyboard.isDown("space") then
      show = true
    end
  if timer > 2 then
    timer = 0
  end
end

function love.draw()
  if show then
    love.graphics.rectangle("fill", 100, 100, 100, 100)
  end
end

Il me donne l’erreur suivante :

Un end est attendu quelque part
Un end est attendu quelque part

<eof> signifie fin de fichier. Il attend end à la fin du fichier. Est-ce ainsi que nous le corrigeons, en mettant end à la fin du fichier? Et bien non. Quelque part, j’ai foiré et nous devons le réparer correctement. Il dit qu’il s’attend à ce que end ferme la fonction à la ligne 6, alors commençons à partir de là et descendons. Après avoir ouvert la fonction, je démarre une instruction if, puis une autre instruction if. Je ferme la deuxième instruction if et commence une autre instruction if. Je ferme également cette instruction if, puis je ferme l’instruction if externe. Non, attendez, ce n’est pas vrai. Je devrais fermer la fonction à ce stade. J’ai oublié d’ajouter end quelque part dans la fonction. Permettez-moi de résoudre ce problème.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function love.update(dt)
  show = false
  timer = timer + dt

  if timer > 1 then
    if love.keyboard.isDown("space") then
      show = true
    end
    if timer > 2 then
      timer = 0
    end
  end
end

Et maintenant ça marche. C’est pourquoi l’indentation dans votre code est si importante. Cela vous aide à voir où vous avez fait une erreur comme celle-ci.

Une autre erreur courante est l’une des suivantes :

1
2
3
4
function love.load()
  t = {}
  table.insert(t, {x = 100, y = 50)
end

Qui me donne l’erreur suivante :

Erreur de syntaxe car il manque un } ou une )
Erreur de syntaxe car il manque un } ou une )

C’est parce que je n’ai pas fermé les accolades.

1
2
3
4
function love.load()
  t = {}
  table.insert(t, {x = 100, y = 50})
end

Demander de l’aide

Maintenant, vous avez peut-être un bug et vous ne pouvez pas le corriger. Vous avez essayé de le déboguer, mais vous ne comprenez tout simplement pas pourquoi cela ne fonctionnera pas et vous avez l’impression d’avoir besoin d’aide. Eh bien, heureusement pour vous, il y a beaucoup de gens sur Internet qui seront heureux de vous aider. Les meilleurs endroits pour poser votre question sont sur les forums ou dans Discord. Mais poser une question n’est pas simplement demander « Hé les gars, j’ai ce bug là où ça se passe, que dois-je faire ? ». Vous devez leur fournir des informations qu’ils peuvent utiliser pour vous aider. Par exemple :

  • Qu’est-ce qui ne va pas exactement et qu’attendez-vous / voulez-vous qu’il se passe ?
  • Expliquez ce que vous avez essayé de faire jusqu’à présent pour y remédier.
  • Montrez le code de l’endroit où (vous pensez) qu’il va mal.
  • Partagez le fichier .love afin que d’autres personnes puissent l’essayer.

Mais avant de demander de l’aide, vous pouvez rechercher votre question n’a pas déjà été posée. Il se peut qu’elle soit courante et pour laquelle il y a beaucoup de réponses.

Et rappelez-vous, personne n’est obligé de vous aider, et ceux qui le font, tous le font gratuitement, alors soyez gentil 🙂

Débogage avec le canard en caoutchouc

Vous pouvez également obtenir un canard en caoutchouc. Il existe ce qu’on appelle le débogage du canard en caoutchouc. L’idée est que lorsque vous expliquez ce que vous faites dans votre code, vous vous rendez souvent compte de ce que vous faites mal et corrigez le bogue vous-même. Donc, au lieu de l’expliquer à quelqu’un, vous l’expliquez à votre canard en caoutchouc. J’ai moi-même un canard en caoutchouc, il s’appelle Hendrik !

Canard en plastique
Canard en plastique

Résumé

Nous pouvons utiliser print pour trouver la source de notre bug. Un message d’erreur nous indique exactement ce qui ne va pas. Les erreurs de syntaxe sont des erreurs qui se produisent car il ne peut pas « lire » correctement le code. L’indentation est utile car elle nous empêche d’obtenir des erreurs de fin de ligne. Nous pouvons demander de l’aide sur Internet, mais nous devons fournir suffisamment d’informations sur ce qui se passe pour rendre les choses moins difficiles pour les personnes qui nous aident.