541 lines
20 KiB
Text
541 lines
20 KiB
Text
[#_lesson_3_making_decisions]
|
||
== Leçon 3 : Prendre des décisions
|
||
|
||
image::learn/03-decisions.png[La leçon terminée, 480]
|
||
|
||
Tout ce que vous avez écrit jusqu'ici fait la même chose à chaque image. Le mot
|
||
de la leçon deux bougeait, que vous le vouliez ou non, et la seule raison pour
|
||
laquelle il faisait demi-tour, c'étaient quatre blocs de code qu'on vous avait
|
||
demandé de croire sur parole.
|
||
|
||
Cette leçon, ce sont ces quatre blocs, expliqués pour de bon. À la fin, votre
|
||
programme posera des questions, agira selon les réponses, et -- parce que la
|
||
question la plus intéressante qu'un jeu puisse poser est « que fait le
|
||
joueur ? » -- vous piloterez une boîte dans la fenêtre avec les touches
|
||
fléchées. Gardez cette boîte. C'est le joueur du jeu que vous construirez à la
|
||
leçon sept.
|
||
|
||
[#_start_a_new_folder_2]
|
||
=== Créez un nouveau dossier
|
||
|
||
Un dossier appelé `decisions`, dedans un fichier appelé `decisions.singe`, et
|
||
`Singe -R decisions` qui tourne dans un terminal. Comme la dernière fois.
|
||
|
||
[#_what_an_if_really_says]
|
||
=== Ce que dit vraiment un `if`
|
||
|
||
Voici le bloc de la leçon deux, tout seul.
|
||
|
||
[source,lua]
|
||
----
|
||
if wordX > lastColumn then
|
||
wordX = lastColumn
|
||
end
|
||
----
|
||
|
||
Quatre parties. Le mot `if`. Une question. Le mot `then`. Et un corps de lignes
|
||
qui ne s'exécutent que lorsque la réponse à la question est oui, fermé par
|
||
`end`.
|
||
|
||
La question est `wordX > lastColumn`, et c'est le `>` qui fait le vrai travail.
|
||
Il compare les deux nombres de part et d'autre et produit une réponse qui est
|
||
soit *vrai*, soit *faux*. Ces deux mots ne sont ni du texte ni des nombres ; ce
|
||
sont des valeurs à part entière, appelées *booléens*, et un booléen est la seule
|
||
chose qui intéresse un `if`.
|
||
|
||
L'indentation, c'est la même idée qu'à la leçon un : les lignes à l'intérieur
|
||
sont indentées pour que vous voyiez d'un coup d'œil ce qui appartient au `if`,
|
||
et le `end` s'aligne sur le `if` qui l'a ouvert. Lua l'exécuterait sans les
|
||
espaces. Vous, vous ne pourriez pas le lire.
|
||
|
||
Il y a six de ces comparaisons, et vous les utiliserez toutes.
|
||
|
||
[cols="1,4"]
|
||
|===
|
||
| `a < b` | a est plus petit que b
|
||
| `a > b` | a est plus grand que b
|
||
| `a <= b` | a est plus petit que b ou égal à b
|
||
| `a >= b` | a est plus grand que b ou égal à b
|
||
| `a == b` | a est la même chose que b
|
||
| `a ~= b` | a n'est pas la même chose que b
|
||
|===
|
||
|
||
Ce sont les deux dernières qui demandent de la prudence, pour des raisons
|
||
différentes.
|
||
|
||
`~=` veut dire « n'est pas égal à ». La plupart des langages l'écrivent `!=`, et
|
||
si vous avez déjà vu un programme, vos doigts taperont `!=` et Lua le refusera.
|
||
Le tortillon se trouve sur votre clavier à côté du `1` ou sous le `#`, selon
|
||
l'endroit où vous vivez.
|
||
|
||
`==`, ce sont deux signes égal, et ce n'est pas une faute de frappe pour un
|
||
seul. C'est l'une des erreurs les plus courantes en programmation, et elle
|
||
mérite qu'on s'y arrête un instant.
|
||
|
||
À la leçon deux, vous avez appris qu'un seul signe égal veut dire *mettez le
|
||
côté droit dans le nom de gauche*. C'est une chose que vous faites. Ça change
|
||
quelque chose.
|
||
|
||
Deux signes égal veulent dire *ces deux-là sont-ils les mêmes ?* C'est une
|
||
question que vous posez. Ça ne change rien, et ça renvoie vrai ou faux.
|
||
|
||
[source,lua]
|
||
----
|
||
lives = 3
|
||
if lives == 3 then
|
||
----
|
||
|
||
La première ligne met `lives` à trois. La seconde demande s'il vaut trois. Des
|
||
travaux différents, des symboles différents, à un caractère près. Lua vous
|
||
attrapera si vous les confondez, et vous rencontrerez l'erreur qu'il emploie à
|
||
la fin de cette leçon.
|
||
|
||
[#_when_the_answer_is_no]
|
||
=== Quand la réponse est non
|
||
|
||
Un `if` tout seul ne fait rien du tout quand la réponse est fausse. Très
|
||
souvent, vous voulez que l'autre chose se produise à la place, et c'est `else`.
|
||
|
||
[source,lua]
|
||
----
|
||
if lives > 0 then
|
||
message = "Ready"
|
||
else
|
||
message = "Game Over"
|
||
end
|
||
----
|
||
|
||
Exactement un de ces deux corps s'exécute, jamais les deux, jamais aucun, donc
|
||
`message` finit toujours par contenir l'une des deux chaînes, et jamais rien.
|
||
|
||
Quand il y a plus de deux possibilités, `elseif` les enchaîne.
|
||
|
||
[source,lua]
|
||
----
|
||
if score >= 10000 then
|
||
rank = "ace"
|
||
elseif score >= 5000 then
|
||
rank = "pilot"
|
||
elseif score >= 1000 then
|
||
rank = "rookie"
|
||
else
|
||
rank = "passenger"
|
||
end
|
||
----
|
||
|
||
Lua essaie les questions en partant du haut et s'arrête à la première qui est
|
||
vraie. Un score de 6000 n'est pas plus grand que 10000, donc il essaie la
|
||
suivante, qui est vraie, donc `rank` devient `pilot` et les deux autres
|
||
questions ne sont jamais posées. Ce dernier point compte : le `elseif` pour 1000
|
||
est vrai aussi pour un score de 6000, et il n'est jamais atteint, c'est pourquoi
|
||
l'ordre va du plus grand au plus petit.
|
||
|
||
Toute la chaîne n'a besoin que d'un seul `end`, quel que soit le nombre de
|
||
parties `elseif` qu'elle contient. C'est une seule décision, pas quatre.
|
||
|
||
[#_true_false_and_nothing_at_all]
|
||
=== Vrai, faux et rien du tout
|
||
|
||
Pas besoin de comparer deux choses pour obtenir un booléen. Vous pouvez en
|
||
garder un.
|
||
|
||
[source,lua]
|
||
----
|
||
paused = false
|
||
----
|
||
|
||
C'est une variable comme une autre, et la valeur qu'elle contient est le booléen
|
||
`false` lui-même, écrit sans guillemets parce que ce n'est pas le mot « false »,
|
||
c'est l'idée. Il en va de même pour `true`. Une variable qui contient l'un des
|
||
deux peut aller directement dans un `if`, sans aucune comparaison :
|
||
|
||
[source,lua]
|
||
----
|
||
if paused then
|
||
----
|
||
|
||
Lisez-le « si paused ». Ça se lit mieux que `if paused == true`, qui fait la
|
||
même chose par le chemin le plus long, et les programmeurs expérimentés vous
|
||
regarderont bizarrement si vous l'écrivez.
|
||
|
||
Trois mots combinent et inversent ces réponses.
|
||
|
||
[source,lua]
|
||
----
|
||
if alive and not shielded then
|
||
if coins > 0 or freePlay then
|
||
----
|
||
|
||
`and` est vrai quand les deux côtés le sont. `or` est vrai quand l'un des côtés
|
||
l'est, ou les deux. `not` change vrai en faux et faux en vrai. Ils se lisent
|
||
comme de l'anglais et, chose rare en programmation, ils veulent dire ce qu'ils
|
||
veulent dire en anglais.
|
||
|
||
Il reste une valeur à connaître, et c'est celle qui produit les erreurs les plus
|
||
déroutantes de votre première année.
|
||
|
||
[source,lua]
|
||
----
|
||
overlayPrint(0, 0, "lives " .. tostring(lives))
|
||
----
|
||
|
||
Si vous n'avez jamais rien mis dans `lives`, ça affiche `lives nil`. Lua ne se
|
||
plaint pas d'un nom qu'il n'a jamais vu ; il vous donne `nil`, qui est son mot
|
||
pour *rien ici*. Ce n'est pas zéro et ce n'est pas une chaîne vide. Zéro est un
|
||
nombre que vous avez voulu ranger. `nil`, c'est l'absence de valeur.
|
||
|
||
Vous avez déjà rencontré `nil` deux fois sans qu'on vous le dise.
|
||
`frames = frames + 1` sans la ligne `frames = 0` au-dessus échoue parce que vous
|
||
avez demandé à Lua d'ajouter un à rien. Et un callback mal orthographié est
|
||
`nil` lui aussi, c'est pourquoi un `onOverlayUpdate` mal écrit vous donne une
|
||
fenêtre noire et aucune erreur : Singe cherche le nom, n'y trouve rien, et
|
||
poursuit tranquillement sa journée.
|
||
|
||
`tostring` est dans cette ligne parce que `..` ne joint un booléen ou un `nil` à
|
||
rien du tout. Les nombres, il les convertit pour vous ; ceux-là, non. C'était la
|
||
promesse de la fin de la leçon deux, et maintenant vous en avez l'usage.
|
||
|
||
Enfin, la règle qui relie toute cette partie, parce que `if` accepte tout ce que
|
||
vous lui donnez, pas seulement vrai et faux :
|
||
|
||
[quote]
|
||
Tout est vrai en Lua, sauf `false` et `nil`.
|
||
|
||
Zéro est vrai. Une chaîne vide est vraie. Seuls ces deux-là ne le sont pas, et
|
||
une fois que vous le savez, `if movingLeft then` se lit parfaitement, que
|
||
`movingLeft` contienne `true`, `false`, ou n'ait jamais été rempli du tout.
|
||
|
||
[#_reading_the_controls]
|
||
=== Lire les commandes
|
||
|
||
Il est temps de demander quelque chose au joueur. Il faut pour ça un nouveau
|
||
callback.
|
||
|
||
[source,lua]
|
||
----
|
||
function onInputPressed(what)
|
||
if what == SWITCH_RIGHT then
|
||
boxX = boxX + 10
|
||
end
|
||
end
|
||
----
|
||
|
||
`onInputPressed` est le deuxième callback que vous écrivez, et il marche
|
||
exactement comme la leçon un l'a décrit : vous l'écrivez, Singe l'appelle.
|
||
`onOverlayUpdate` est appelé à intervalles réguliers. Celui-ci est appelé quand
|
||
quelque chose se passe -- quand le joueur appuie sur n'importe quoi que le
|
||
moteur reconnaît.
|
||
|
||
La différence avec `onOverlayUpdate`, c'est le mot entre les parenthèses. Singe
|
||
doit vous dire *quelle* commande a été enfoncée, alors il passe une valeur à la
|
||
fonction, et `what` est le nom sous lequel vous avez choisi de la recevoir. La
|
||
leçon un appelait arguments les choses que vous passez à une fonction ; vu de
|
||
l'intérieur, le nom qui en attrape un est un *paramètre*. Le nom est à vous :
|
||
appelez-le `what`, appelez-le `button`, appelez-le `k`. Singe le remplit dans
|
||
tous les cas.
|
||
|
||
`SWITCH_RIGHT` est un nom que le moteur a déjà donné à une valeur, comme
|
||
`OVERLAY_UPDATED` à la leçon un. Vous n'avez rien à charger pour vous en servir ;
|
||
Singe les définit tous avant que votre script s'exécute. Il y en a un pour tout
|
||
ce qu'a une borne :
|
||
`SWITCH_LEFT`, `SWITCH_RIGHT`, `SWITCH_UP`, `SWITCH_DOWN`, de `SWITCH_BUTTON1`
|
||
à `SWITCH_BUTTON4`, `SWITCH_START1`, `SWITCH_COIN1`, et d'autres encore. Le
|
||
tableau Constantes du moteur de la référence couvre toute la famille, qui va de
|
||
`SWITCH_UP` à `SWITCH_RECORD`. Ils ne s'appellent pas « la flèche droite », et c'est
|
||
voulu, parce que le même `SWITCH_RIGHT` arrive, que le joueur ait poussé une
|
||
touche fléchée, un joystick ou le stick d'une manette. Vous écrivez le jeu une
|
||
fois et il marche sur les trois.
|
||
|
||
Ajoutez ce callback, donnez à `boxX` une valeur de départ en dehors des
|
||
fonctions, et dessinez quelque chose à `boxX`. Appuyez sur la flèche droite. La
|
||
boîte saute de dix pixels à chaque appui.
|
||
|
||
[#_it_happened_and_it_is_happening]
|
||
=== C'est arrivé, et c'est en train d'arriver
|
||
|
||
Gardez la touche fléchée enfoncée. Il ne se passe rien de plus.
|
||
|
||
`onInputPressed` est appelé une fois, quand la touche descend, et pas une
|
||
seconde fois avant que vous l'ayez lâchée et enfoncée de nouveau. Il n'y a pas
|
||
de répétition automatique. C'est exactement ce qu'il faut pour certaines
|
||
choses -- tirer, insérer une pièce, choisir un élément de menu -- et exactement
|
||
ce qu'il ne faut pas pour marcher, qui doit continuer tant que la touche est
|
||
tenue.
|
||
|
||
Ce sont deux questions vraiment différentes. *C'est arrivé*, c'est un
|
||
événement, et vous l'apprenez une fois. *C'est en train d'arriver*, c'est un
|
||
état, et ça dure. Singe vous informe des événements, et la façon de transformer
|
||
des événements en état, c'est de vous en souvenir vous-même.
|
||
|
||
Deux callbacks, une variable entre eux.
|
||
|
||
[source,lua]
|
||
----
|
||
movingRight = false
|
||
|
||
|
||
function onInputPressed(what)
|
||
if what == SWITCH_RIGHT then
|
||
movingRight = true
|
||
end
|
||
end
|
||
|
||
|
||
function onInputReleased(what)
|
||
if what == SWITCH_RIGHT then
|
||
movingRight = false
|
||
end
|
||
end
|
||
----
|
||
|
||
`onInputReleased` est le troisième callback, et c'est le miroir du deuxième :
|
||
Singe l'appelle quand la touche remonte, avec la même valeur `SWITCH_`. À eux
|
||
deux, ils font que `movingRight` dit la vérité sur ce que fait le doigt du
|
||
joueur à cet instant.
|
||
|
||
Rien n'a encore bougé, et c'est voulu. Appuyer et bouger sont maintenant deux
|
||
travaux séparés. Le mouvement va là où va tout le travail de chaque image.
|
||
|
||
[source,lua]
|
||
----
|
||
function onOverlayUpdate()
|
||
if movingRight then
|
||
boxX = boxX + BOX_SPEED
|
||
end
|
||
...
|
||
----
|
||
|
||
La boîte glisse maintenant en douceur tant que la touche est enfoncée, à une
|
||
vitesse que vous choisissez, et l'arithmétique est revenue dans la fonction qui
|
||
s'exécute soixante fois par seconde, là où est sa place. Cette forme -- les
|
||
événements lèvent des drapeaux, l'image agit selon les drapeaux -- est la façon
|
||
dont presque tous les jeux gèrent leurs commandes, et vous vous en servirez de
|
||
nouveau dans chaque leçon où il y a un joueur.
|
||
|
||
[#_drawing_a_box]
|
||
=== Dessiner une boîte
|
||
|
||
`overlayBox` prend deux coins : la gauche et le haut du rectangle, puis la
|
||
droite et le bas.
|
||
|
||
[source,lua]
|
||
----
|
||
colorForeground(255, 220, 0)
|
||
overlayBox(boxX, boxY, boxX + BOX_SIZE, boxY + BOX_SIZE)
|
||
----
|
||
|
||
Elle dessine un *contour*, quatre traits d'un pixel d'épaisseur, et non un
|
||
rectangle plein. Il n'y a aucun rectangle plein parmi les appels de dessin de
|
||
l'overlay. Quand vous voudrez un bloc plein plus tard, il y a des façons d'en
|
||
obtenir un, et la leçon neuf présente la façon habituelle.
|
||
|
||
Ses nombres sont des pixels, pas des cellules de caractère. Ça piège du monde,
|
||
parce que `overlayPrint`, à la leçon deux, comptait en cellules de six pixels
|
||
sur treize, et tout le reste de Singe compte en pixels. C'est `overlayPrint`
|
||
l'exception ; les autres appels de dessin -- `overlayBox`, `overlayLine`,
|
||
`overlayCircle`, `overlayEllipse` et `overlayPlot` -- travaillent tous dans les
|
||
mêmes pixels que ceux qu'indique `overlayGetWidth`.
|
||
|
||
`colorForeground` règle la couleur, avec trois nombres de 0 à 255 : combien de
|
||
rouge, combien de vert, combien de bleu. Les trois à 255, c'est du blanc, tous à
|
||
0, c'est du noir, et `(255, 220, 0)` est un jaune chaud. Remarquez que ce n'est
|
||
pas un argument passé à `overlayBox`. C'est un réglage : vous le changez, et
|
||
tout ce que vous dessinez ensuite sort dans la nouvelle couleur jusqu'à ce que
|
||
vous le changiez de nouveau. `overlayPrint` fait encore exception -- la police
|
||
de console arrive avec ses propres couleurs intégrées et ne vous écoute pas.
|
||
|
||
[#_the_whole_thing_2]
|
||
=== Le tout
|
||
|
||
[source,lua]
|
||
----
|
||
BOX_SIZE = 20
|
||
BOX_SPEED = 2
|
||
|
||
width = overlayGetWidth()
|
||
height = overlayGetHeight()
|
||
maxX = width - BOX_SIZE - 1
|
||
maxY = height - BOX_SIZE - 1
|
||
|
||
boxX = width // 2
|
||
boxY = height // 2
|
||
|
||
movingLeft = false
|
||
movingRight = false
|
||
movingUp = false
|
||
movingDown = false
|
||
|
||
|
||
function onInputPressed(what)
|
||
if what == SWITCH_LEFT then
|
||
movingLeft = true
|
||
elseif what == SWITCH_RIGHT then
|
||
movingRight = true
|
||
elseif what == SWITCH_UP then
|
||
movingUp = true
|
||
elseif what == SWITCH_DOWN then
|
||
movingDown = true
|
||
end
|
||
end
|
||
|
||
|
||
function onInputReleased(what)
|
||
if what == SWITCH_LEFT then
|
||
movingLeft = false
|
||
elseif what == SWITCH_RIGHT then
|
||
movingRight = false
|
||
elseif what == SWITCH_UP then
|
||
movingUp = false
|
||
elseif what == SWITCH_DOWN then
|
||
movingDown = false
|
||
end
|
||
end
|
||
|
||
|
||
function onOverlayUpdate()
|
||
if movingLeft and not movingRight then
|
||
boxX = boxX - BOX_SPEED
|
||
elseif movingRight and not movingLeft then
|
||
boxX = boxX + BOX_SPEED
|
||
end
|
||
|
||
if movingUp and not movingDown then
|
||
boxY = boxY - BOX_SPEED
|
||
elseif movingDown and not movingUp then
|
||
boxY = boxY + BOX_SPEED
|
||
end
|
||
|
||
if boxX < 0 then
|
||
boxX = 0
|
||
elseif boxX > maxX then
|
||
boxX = maxX
|
||
end
|
||
|
||
if boxY < 0 then
|
||
boxY = 0
|
||
elseif boxY > maxY then
|
||
boxY = maxY
|
||
end
|
||
|
||
overlayClear()
|
||
|
||
if movingLeft or movingRight or movingUp or movingDown then
|
||
colorForeground(255, 220, 0)
|
||
else
|
||
colorForeground(80, 160, 255)
|
||
end
|
||
|
||
overlayBox(boxX, boxY, boxX + BOX_SIZE, boxY + BOX_SIZE)
|
||
overlayPrint(0, 0, "x " .. boxX .. " y " .. boxY)
|
||
return OVERLAY_UPDATED
|
||
end
|
||
----
|
||
|
||
Quatre choses là-dedans méritent un second regard.
|
||
|
||
`movingLeft and not movingRight` est là parce qu'un joueur peut tenir les deux
|
||
flèches à la fois. Sans le `not`, les deux se battraient et la boîte tremblerait
|
||
ou dériverait ; avec, tenir les deux veut dire qu'aucune ne gagne et que la
|
||
boîte reste immobile, ce qu'un joueur attend.
|
||
|
||
`maxX` est calculé une fois en haut, avec `overlayGetWidth` comme à la leçon
|
||
deux, et le `- 1` est là parce que le dernier pixel de la surface vaut un de
|
||
moins que sa largeur. Enlevez le `- 1` et le bord droit de la boîte tombe hors
|
||
de la surface et disparaît, parce que Singe jette sans se plaindre tout ce que
|
||
vous dessinez en dehors de l'overlay.
|
||
|
||
Les blocs de limitation utilisent `elseif` plutôt que deux blocs `if` séparés.
|
||
La boîte ne peut pas dépasser le bord gauche et le bord droit en même temps,
|
||
donc poser la deuxième question quand la première était vraie, c'est du travail
|
||
perdu.
|
||
|
||
Et la décision de couleur est un `if` dont le seul travail est de choisir une
|
||
valeur. Jaune quand le joueur fait quelque chose, bleu quand il ne fait rien, ce
|
||
qui est un moyen gratuit de voir que votre gestion des commandes marche
|
||
vraiment.
|
||
|
||
[#_try_it_3]
|
||
=== Essayez
|
||
|
||
. *Changez la vitesse.* `BOX_SPEED = 1` et `BOX_SPEED = 8`. À huit, regardez ce
|
||
que fait la limitation quand vous poussez la boîte dans un coin.
|
||
. *Affichez vos drapeaux.* Ajoutez une ligne à `onOverlayUpdate` :
|
||
`overlayPrint(0, 1, "left " .. tostring(movingLeft))`. Tenez puis relâchez la
|
||
flèche gauche et regardez-le basculer. Puis enlevez le `tostring` et lisez
|
||
l'erreur que Lua vous donne.
|
||
. *Accélérez quand un bouton est enfoncé.* Ajoutez un drapeau `running` piloté
|
||
par `SWITCH_BUTTON1` dans les deux callbacks d'entrée, et utilisez un `if`
|
||
dans `onOverlayUpdate` pour avancer de deux fois `BOX_SPEED` tant qu'il est
|
||
vrai.
|
||
. *Marquez le milieu.* Dessinez une deuxième boîte, petite, au centre de la
|
||
fenêtre, qui change de couleur quand la boîte du joueur la chevauche. Il vous
|
||
faudra `and` pour combiner quatre comparaisons, et c'est plus difficile qu'il
|
||
n'y paraît. Se tromper un peu est normal ; la leçon onze le fait
|
||
correctement.
|
||
. *Retirez les relâchements.* Supprimez toute la fonction `onInputReleased` et
|
||
lancez. La boîte fait un pas et ne s'arrête plus jamais. Trouvez quelle ligne
|
||
n'est maintenant jamais atteinte.
|
||
|
||
[#_break_it_on_purpose_3]
|
||
=== Cassez-le exprès
|
||
|
||
Trouvez le bloc de limitation et remplacez le `<` de sa première comparaison
|
||
par un seul signe égal, pour qu'elle devienne :
|
||
|
||
[source,lua]
|
||
----
|
||
if boxX = 0 then
|
||
----
|
||
|
||
Enregistrez-le. La fenêtre reste vide et le terminal affiche :
|
||
|
||
----
|
||
Error running script: decisions/decisions.singe:57: 'then' expected near '='
|
||
----
|
||
|
||
C'est l'erreur contre laquelle tout le passage sur `==` vous mettait en garde,
|
||
et le message est un bon exemple d'erreur parfaitement exacte et parfaitement
|
||
inutile si vous la prenez au pied de la lettre. Lua ne vous demande pas
|
||
d'ajouter le mot `then`. Lua est allé jusqu'à `if boxX`, attendait ensuite une
|
||
comparaison ou un `then`, et a trouvé `=`, qui ne peut être ni l'un ni l'autre.
|
||
|
||
Chaque fois que vous voyez `'then' expected` après un `if`, cherchez un `=`
|
||
simple qui devrait être double. C'est presque toujours ça.
|
||
|
||
Remarquez où celle-ci est apparue : le jeu n'a jamais démarré, comme pour la
|
||
chaîne non terminée de la leçon un, parce que Lua ne pouvait pas lire le
|
||
fichier. L'erreur du compteur d'images de la leçon deux s'est produite pendant
|
||
l'exécution. Les erreurs dans la forme de votre code vous arrêtent avant que le
|
||
jeu démarre. Les erreurs dans ce que fait votre code attendent qu'il tourne.
|
||
|
||
[#_what_you_learned_3]
|
||
=== Ce que vous avez appris
|
||
|
||
* `if question then ... end` n'exécute un corps que quand la réponse est vraie.
|
||
* `else` donne l'autre cas, et `elseif` en enchaîne d'autres ; la première
|
||
question vraie gagne et les autres ne sont jamais posées.
|
||
* Les comparaisons sont `<`, `>`, `<=`, `>=`, `==` et `~=`.
|
||
* `=` met une valeur dans un nom. `==` demande si deux choses sont les mêmes.
|
||
* `true` et `false` sont des valeurs, et vous pouvez les garder dans des
|
||
variables.
|
||
* `and`, `or` et `not` combinent et inversent ces réponses.
|
||
* `nil` est ce que vous obtenez d'un nom que vous n'avez jamais rempli, et ce
|
||
n'est pas zéro.
|
||
* Tout est vrai, sauf `false` et `nil`.
|
||
* `onInputPressed` et `onInputReleased` sont des callbacks que Singe appelle
|
||
avec une valeur `SWITCH_` quand le joueur appuie sur une commande ou la
|
||
relâche.
|
||
* Un appui est un événement et n'arrive qu'une fois ; gardez l'état dans une
|
||
variable et agissez selon lui à chaque image.
|
||
* `overlayBox` dessine un contour en pixels, et `colorForeground` est un
|
||
réglage, pas un argument.
|
||
|
||
[#_next_time_3]
|
||
=== La prochaine fois
|
||
|
||
Une boîte, c'est facile. Cent étoiles, non, du moins pas de la façon dont vous
|
||
avez écrit les choses jusqu'ici, parce que taper cent lignes `overlayPlot`
|
||
n'est pour personne l'idée d'une bonne soirée. La leçon quatre, c'est la
|
||
boucle : dire à l'ordinateur de faire la même chose de nombreuses fois, avec
|
||
quelque chose de différent à chaque tour, et c'est ce qui rend possible un
|
||
écran rempli de n'importe quoi.
|