299 lines
12 KiB
Text
299 lines
12 KiB
Text
[#_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.
|