singe/docs/fr/lessons/01-hello.adoc

299 lines
12 KiB
Text
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[#_lesson_1_hello]
== Leçon 1 : Bonjour
image::learn/01-hello.png[La leçon terminée, 480]
Voilà ce que vous aurez à la fin de cette leçon. Ça ne paie pas de mine. C'est
aussi un programme que vous avez écrit, qui tourne sur un vrai moteur de jeu, et
tout le reste de ce livre repose sur les cinq lignes qui l'ont produit.
[#_set_up_your_work_folder]
=== Préparez votre dossier de travail
Créez un dossier pour tout y ranger, appelé `singe` ou comme il vous plaira, et
mettez-y votre copie de Singe. C'est votre *dossier de travail*, et chaque leçon
de ce livre y ajoute un nouveau dossier. Vous le créerez une fois et n'y
penserez plus jamais.
Dans le dossier de travail, créez un dossier appelé `hello`, et dans celui-ci un
fichier appelé `hello.singe`.
[literal]
----
singe/ <- votre dossier de travail, avec Singe dedans
hello/
hello.singe
----
Cette imbrication n'est pas une lubie. Singe considère le dossier depuis lequel
vous le lancez comme l'endroit où vivent les jeux, un dossier par jeu, et il y
range aussi ses propres fichiers. Votre jeu va dans son propre dossier, un
niveau plus bas. À partir de la leçon deux, chaque leçon est un autre dossier à
côté de `hello`.
Deux choses à propos des noms. La partie après le point, `.singe`, est ce qui
indique à Singe qu'il s'agit d'un script. Et sur la plupart des ordinateurs qui
ne sont pas sous Windows, les majuscules comptent : `Hello.singe` et
`hello.singe` sont deux fichiers différents. Prenez dès maintenant l'habitude de
taper les noms exactement.
Donner le même nom au dossier et au script compte aussi, et vous allez voir
pourquoi dans un instant.
Ouvrez `hello.singe` dans votre éditeur de texte. Il est vide. C'est bien comme
ça.
[#_type_this_in]
=== Tapez ceci
[source,lua]
----
function onOverlayUpdate()
overlayClear()
overlayPrint(2, 2, "Hello!")
return OVERLAY_UPDATED
end
----
Enregistrez-le.
Ne vous souciez pas encore de ce que tout cela veut dire. Deux choses méritent
d'être remarquées avant de le lancer, parce qu'elles seront vraies de chaque
programme que vous écrirez.
La première, c'est que les espaces au début des trois lignes du milieu sont là
exprès. Ils ne changent rien du tout au programme -- Singe le lancerait
exactement pareil sans eux -- mais ils vous montrent d'un coup d'œil que ces
trois lignes sont *à l'intérieur* de ce qui commence par `function` et finit par
`end`. Tous les programmeurs font ça. Faites-le dès le premier jour et vous
n'aurez jamais à l'apprendre plus tard.
La seconde, c'est l'ordre des lignes. Elles s'exécutent de haut en bas, l'une
après l'autre, comme les étapes d'une recette. C'est la chose la plus importante
à savoir sur un programme, et presque tout ce qui embrouille un débutant vient
de ce qu'il l'oublie.
[#_run_it]
=== Lancez-le
Ouvrez un terminal, allez dans votre *dossier de travail* -- pas dans le dossier
`hello` qu'il contient -- et donnez le nom du dossier que vous voulez lancer :
----
Singe hello
----
Sous Windows, c'est `Singe.exe hello`. Si votre copie de Singe se trouve
ailleurs, tapez le chemin qui y mène, par exemple `../Singe hello`.
Voilà pourquoi le dossier et le script portent le même nom. Quand on lui donne
un dossier, Singe y cherche un script qui s'appelle pareil. Nommez-les
différemment et vous obtenez `Error: Unable to locate the game.`, c'est-à-dire
le moteur qui vous dit qu'il a cherché et n'a rien trouvé qu'il reconnaisse.
Vous pouvez toujours être explicite à la place et écrire
`Singe hello/hello.singe`, qui fait la même chose.
Une fenêtre noire s'ouvre avec le mot `Hello!` près du coin supérieur gauche.
Appuyez sur *Échap* ou *Q* pour quitter.
Deux choses se seront produites sans que vous les ayez demandées, et elles sont
toutes les deux normales. Des dossiers appelés `Singe` et `data` sont apparus
dans votre dossier de travail, à côté de `hello` : le premier, c'est le moteur
qui extrait les fichiers dont il a besoin, le second, c'est là qu'ira tout ce
que vos jeux sauvegardent. Laissez-les tous les deux tranquilles. Et la fenêtre
est presque entièrement noire, parce que vous n'avez rien dessiné à part six
caractères.
[#_what_just_happened]
=== Ce qui vient de se passer
Maintenant, les cinq lignes, une par une.
[source,lua]
----
function onOverlayUpdate()
----
`function` commence un groupe d'instructions et lui donne un nom. Tout ce qui se
trouve d'ici jusqu'au `end` correspondant en fait partie. Cette fonction
s'appelle `onOverlayUpdate`, et les parenthèses vides après le nom prendront
leur sens à la leçon cinq.
Ce nom, ce n'est pas à vous de le choisir. Singe cherche une fonction qui porte
exactement ce nom et l'appelle une soixantaine de fois par seconde, sans fin,
pour vous donner l'occasion de dessiner. Si vous l'écrivez `onoverlayupdate` ou
`onOverlayUpdated`, Singe ne la trouvera pas, votre fenêtre restera noire, et
rien ne vous dira que vous vous êtes trompé. C'est la première vraie leçon :
l'ordinateur fait ce que vous avez écrit, pas ce que vous vouliez dire.
Une fonction que vous écrivez et que le moteur appelle est un *callback* (une
fonction de rappel). Vous ne l'appelez pas vous-même, et vous ne pouvez pas dire
quand elle s'exécute ; vous l'écrivez, et Singe vous rappelle quand il y a
quelque chose à faire. Chaque nom de ce livre qui commence par `on` est un
callback, et il y en a un pour presque tout ce qui peut arriver : un bouton
enfoncé, une touche tapée, un son qui se termine, le disque qui atteint une
image. `onOverlayUpdate` est celui du dessin, et c'est le seul endroit où
dessiner est permis.
[source,lua]
----
overlayClear()
----
C'est aussi une fonction, mais pas une que vous devez écrire : Singe la fournit,
avec plusieurs centaines d'autres, et vous êtes en train de *l'appeler*. Appeler
une fonction, c'est dire son nom suivi de parenthèses. Celle-ci efface l'écran.
Elle vient en premier parce que dessiner ne remplace pas ce qui était là avant,
ça dessine par-dessus. Effacer, puis dessiner, à chaque fois.
[source,lua]
----
overlayPrint(2, 2, "Hello!")
----
Un autre appel, et celui-ci a besoin qu'on lui dise trois choses, qui vont entre
les parenthèses, séparées par des virgules. Les choses que vous passez ainsi à
une fonction s'appellent des *arguments*.
Les deux premières sont des nombres : à quelle distance vers la droite et à
quelle distance vers le bas. La troisième est le texte à afficher, et il est
entre guillemets doubles parce que c'est ainsi qu'on indique à l'ordinateur que
`Hello!` est un morceau de texte et non le nom de quelque chose. Un texte entre
guillemets s'appelle une *chaîne* (de caractères), et vous vous servirez de
chaînes sans arrêt.
Tôt ou tard, vous voudrez mettre un guillemet double à l'intérieur d'une chaîne,
et la manière évidente ne marche pas : le deuxième guillemet termine la chaîne
trop tôt, et vous obtenez la même erreur `unfinished string` que celle que vous
rencontrerez à la fin de cette leçon. Il y a deux façons de la contourner, et
elles valent toutes les deux d'être connues.
[source,lua]
----
overlayPrint(2, 2, "She said \"hello\" to me.")
overlayPrint(2, 4, 'She said "hello" to me.')
----
La première met une barre oblique inverse devant chaque guillemet qui fait
partie du texte. La barre oblique inverse dit « le caractère suivant fait partie
de la chaîne, ce n'est pas sa fin », et la paire s'appelle une *séquence
d'échappement*. La seconde utilise des guillemets simples pour marquer les bouts
de la chaîne, ce qui laisse les guillemets doubles libres d'être du texte
ordinaire. Lua accepte les deux sortes de guillemets, du moment que la chaîne
finit par la même sorte que celle par laquelle elle a commencé.
Ces deux lignes affichent exactement la même chose. Utilisez celle qui se lit
le plus facilement, et c'est en général celle aux guillemets simples quand le
texte est plein de guillemets doubles.
Les deux nombres ne sont pas des pixels. `overlayPrint` est le texte simple
propre au moteur, et il compte en cellules de caractère : `(0, 0)` est le coin
tout en haut à gauche, `(1, 0)` est une lettre plus à droite, et `(0, 1)` une
ligne plus bas. Donc `(2, 2)`, c'est deux lettres vers la droite et deux lignes
vers le bas. D'autres manières de dessiner du texte comptent bien en pixels, et
vous les rencontrerez à la leçon dix-neuf.
[source,lua]
----
return OVERLAY_UPDATED
----
`return` renvoie une réponse à celui qui a appelé la fonction. Singe pose une
seule question à votre `onOverlayUpdate` chaque fois qu'il l'appelle : avez-vous
changé quelque chose ? `OVERLAY_UPDATED` veut dire oui, il faut donc l'afficher.
`OVERLAY_UPDATED` n'a pas de guillemets autour parce que ce n'est pas du texte.
C'est un nom que Singe a déjà donné à une valeur, pour que vous puissiez écrire
quelque chose que vous savez lire au lieu d'un nombre qu'il vous faudrait
retenir.
[source,lua]
----
end
----
La fin qui va avec le `function`. Chaque `function` en a exactement une, et
l'oublier est l'erreur la plus courante qui soit.
[#_try_it]
=== Essayez
Changez une chose à la fois, enregistrez, et relancez. Cette boucle -- changer,
lancer, regarder -- c'est tout le métier.
. *Déplacez le texte.* Changez `overlayPrint(2, 2, "Hello!")` en
`overlayPrint(10, 5, "Hello!")`. Puis essayez `(0, 0)`. Puis essayez
`(200, 2)`, et trouvez pourquoi il a disparu.
. *Dites autre chose.* Mettez votre propre nom entre les guillemets.
. *Dites deux choses.* Ajoutez une deuxième ligne `overlayPrint` sous la
première, avec un autre numéro de ligne et un autre texte. Rien ne vous
empêche d'en avoir autant que vous voulez.
. *Retirez l'effacement.* Supprimez la ligne `overlayClear()` et lancez. Rien ne
change, parce que rien ne bouge encore sur votre écran. Remettez-la quand
même. À la leçon deux, elle comptera énormément, et c'est le bon moment pour
voir que certaines erreurs attendent avant de mordre.
[#_break_it_on_purpose]
=== Cassez-le exprès
Les débutants passent plus de temps à lire des messages d'erreur que des livres
de programmation, alors débarrassons-nous du premier tout de suite.
Supprimez le guillemet fermant après `Hello!`, pour que la ligne devienne
`overlayPrint(2, 2, "Hello!)`, et lancez. Singe refuse de démarrer et dit :
----
Error running script: hello/hello.singe:3: unfinished string near '"Hello!)'
----
Lisez-le à partir de la gauche. `hello/hello.singe`, c'est le fichier : le
dossier, puis le script qu'il contient. `3`, c'est la ligne. Le reste, c'est ce qui n'a pas marché, ici un morceau de texte qui a été
ouvert et jamais fermé. Allez à la ligne trois, remettez le guillemet, et ça
tourne.
Presque toutes les erreurs que vous verrez ont cette forme : un fichier, une
ligne et une plainte. La plainte est parfois écrite pour quelqu'un qui connaît
déjà Lua, mais le fichier et la ligne sont toujours justes, et neuf fois sur dix
la ligne suffit.
[#_stop_restarting_it]
=== Arrêtez de le relancer
Vous avez maintenant démarré Singe à la main cinq ou six fois. Arrêtez. Lancez-le
plutôt comme ceci :
----
Singe -R hello
----
`-R` dit à Singe de surveiller votre script. Enregistrez une modification dans
votre éditeur, et le jeu redémarre de lui-même un instant plus tard avec votre
modification, sans fermer la fenêtre. Si vous enregistrez une erreur, l'erreur
est affichée et la fenêtre reste vide jusqu'à ce que vous enregistriez une
correction.
Utilisez `-R` pour tout le reste de ce livre.
[#_what_you_learned]
=== Ce que vous avez appris
* Un programme est un fichier d'instructions qui s'exécutent dans l'ordre, de
haut en bas.
* Une `function` regroupe des instructions sous un nom et s'arrête à son `end`.
* `onOverlayUpdate` est un nom que Singe cherche et appelle de nombreuses fois
par seconde, et c'est là que va tout votre dessin.
* Appeler une fonction, c'est écrire son nom et des parenthèses. Tout ce qui est
entre les parenthèses est un argument.
* Une fonction que le moteur appelle pour vous, plutôt qu'une que vous appelez
vous-même, est un callback. `onOverlayUpdate` en est un.
* Un texte entre guillemets doubles est une chaîne.
* Effacez l'écran avant de dessiner dessus.
* Une erreur vous donne le fichier et la ligne. Commencez par là.
[#_next_time]
=== La prochaine fois
Votre `Hello!` reste là où vous l'avez mis et ne bouge jamais. Pour le faire
bouger, il vous faut un endroit où garder un nombre qui change -- une
*variable* -- et c'est tout le sujet de la leçon deux.