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

272 lines
12 KiB
Text

[#_lesson_1_hello]
== Lektion 1: Hallo
image::learn/01-hello.png[Die fertige Lektion, 480]
Das hast du am Ende dieser Lektion. Viel her macht es nicht. Es ist aber auch ein Programm,
das du geschrieben hast, und es läuft auf einer echten Spiel-Engine, und alles andere in diesem
Buch baut auf den fünf Zeilen auf, die es gemacht haben.
[#_set_up_your_work_folder]
=== Richte deinen Arbeitsordner ein
Leg einen Ordner an, in dem du alles aufbewahrst, mit dem Namen `singe` oder wie du willst, und
leg deine Kopie von Singe hinein. Das ist dein *Arbeitsordner*, und jede Lektion in diesem Buch
legt darin einen neuen Ordner an. Du legst ihn einmal an und denkst nie wieder darüber nach.
Leg im Arbeitsordner einen Ordner namens `hello` an und darin eine Datei namens
`hello.singe`.
[literal]
----
singe/ <- dein Arbeitsordner, mit Singe darin
hello/
hello.singe
----
Diese Verschachtelung ist keine Pedanterie. Singe behandelt den Ordner, aus dem du es startest,
als den Ort, an dem die Spiele wohnen, ein Ordner pro Spiel, und es legt dort auch seine eigenen
Dateien ab. Dein Spiel kommt in einen eigenen Ordner, eine Ebene tiefer. Ab Lektion zwei ist jede
Lektion ein weiterer Ordner neben `hello`.
Zwei Dinge zu den Namen. Am Teil nach dem Punkt, `.singe`, erkennt Singe, dass das ein Skript
ist. Und auf den meisten Computern, die nicht Windows sind, zählen Großbuchstaben: `Hello.singe`
und `hello.singe` sind zwei verschiedene Dateien. Gewöhn dir gleich jetzt an, Namen genau so
zu tippen, wie sie sind.
Dass Ordner und Skript denselben Namen haben, ist ebenfalls wichtig, und gleich siehst du,
warum.
Öffne `hello.singe` in deinem Texteditor. Die Datei ist leer. Das ist richtig.
[#_type_this_in]
=== Tipp das ein
[source,lua]
----
function onOverlayUpdate()
overlayClear()
overlayPrint(2, 2, "Hello!")
return OVERLAY_UPDATED
end
----
Speichere die Datei.
Mach dir noch keine Gedanken darüber, was das alles bedeutet. Zwei Dinge solltest du bemerken,
bevor du es startest, denn sie gelten für jedes Programm, das du je schreiben wirst.
Das erste: Die Leerzeichen am Anfang der mittleren drei Zeilen sind mit Absicht da. Am Programm
ändern sie überhaupt nichts -- Singe würde es ohne sie genauso ausführen. Aber sie zeigen dir auf
einen Blick, dass diese drei Zeilen *in* das Ding gehören, das mit `function` anfängt und mit
`end` aufhört. Das macht jeder Programmierer. Mach es vom ersten Tag an, dann musst du es später
nie lernen.
Das zweite ist die Reihenfolge der Zeilen. Sie passieren von oben nach unten, eine nach der
anderen, wie die Schritte eines Rezepts. Das ist das Allerwichtigste an einem Programm, und fast
alles, was Anfänger verwirrt, kommt daher, dass sie es vergessen.
[#_run_it]
=== Starte es
Öffne ein Terminal, geh in deinen *Arbeitsordner* -- nicht in den Ordner `hello` darin -- und
nenne den Ordner, den du starten willst:
----
Singe hello
----
Unter Windows ist das `Singe.exe hello`. Wenn deine Kopie von Singe woanders liegt, tipp den Pfad
dorthin, etwa `../Singe hello`.
Darum haben Ordner und Skript denselben Namen. Bekommt Singe einen Ordner, sucht es darin nach
einem Skript, das genauso heißt. Nennst du sie verschieden, bekommst du
`Error: Unable to locate the game.`, und damit sagt die Engine, dass sie nachgesehen und nichts
gefunden hat, was sie kennt. Du kannst stattdessen auch immer alles ausschreiben, `Singe hello/hello.singe`, und das tut
dasselbe.
Ein schwarzes Fenster geht auf, mit dem Wort `Hello!` nahe der linken oberen Ecke. Drück *Esc*
oder *Q*, um es zu beenden.
Zwei Dinge sind passiert, um die du nicht gebeten hast, und beide sind normal. In deinem
Arbeitsordner sind neben `hello` Ordner namens `Singe` und `data` aufgetaucht: Im ersten entpackt
die Engine die Dateien, die sie braucht, im zweiten landet alles, was deine Spiele speichern. Lass
beide in Ruhe. Und das Fenster ist größtenteils schwarz, weil du außer sechs Zeichen nichts
gezeichnet hast.
[#_what_just_happened]
=== Was gerade passiert ist
Jetzt die fünf Zeilen, eine nach der anderen.
[source,lua]
----
function onOverlayUpdate()
----
`function` beginnt eine Gruppe von Anweisungen und gibt ihr einen Namen. Alles von hier bis zum
passenden `end` gehört dazu. Diese hier heißt `onOverlayUpdate`, und die leeren Klammern nach dem
Namen ergeben in Lektion fünf einen Sinn.
Diesen Namen suchst du dir nicht aus. Singe sucht eine Funktion mit genau diesem Namen und ruft sie
etwa sechzigmal pro Sekunde auf, für immer, damit du Gelegenheit zum Zeichnen hast. Schreibst du
sie `onoverlayupdate` oder `onOverlayUpdated`, findet Singe sie nicht, dein Fenster bleibt schwarz,
und nichts sagt dir, dass du einen Fehler gemacht hast. Das ist die erste echte Lektion: Der
Computer tut, was du geschrieben hast, nicht, was du gemeint hast.
Eine Funktion, die du schreibst und die die Engine aufruft, ist ein *Callback*. Du rufst ihn nicht
selbst auf, und du kannst nicht bestimmen, wann er läuft; du schreibst ihn, und Singe ruft dich
zurück, wenn es etwas zu tun gibt. Jeder Name in diesem Buch, der mit `on` anfängt, ist ein
Callback, und es gibt einen für fast alles, was passieren kann: ein gedrückter Knopf, eine
getippte Taste, ein Sound, der zu Ende ist, die Disc, die einen Frame erreicht. `onOverlayUpdate`
ist der fürs Zeichnen, und er ist der einzige Ort, an dem gezeichnet werden darf.
[source,lua]
----
overlayClear()
----
Das ist auch eine Funktion, aber keine, die du schreiben musst: Singe stellt sie bereit, zusammen
mit mehreren hundert anderen, und du *rufst sie auf*. Eine Funktion aufrufen heißt, ihren Namen
hinzuschreiben, gefolgt von Klammern. Diese hier wischt den Bildschirm sauber.
Sie kommt zuerst, weil Zeichnen nicht ersetzt, was vorher da war, sondern darüber zeichnet. Erst
löschen, dann zeichnen, jedes Mal.
[source,lua]
----
overlayPrint(2, 2, "Hello!")
----
Noch ein Aufruf, und diesem muss man drei Dinge sagen, die durch Kommas getrennt in die Klammern
kommen. Dinge, die du einer Funktion so übergibst, heißen *Argumente*.
Die ersten beiden sind Zahlen: wie weit nach rechts und wie weit nach unten. Das dritte ist der
Text, der ausgegeben werden soll, und er steht in doppelten Anführungszeichen, weil du dem Computer
so sagst, dass `Hello!` ein Stück Text ist und nicht der Name von irgendetwas. Text in
Anführungszeichen heißt *String*, und du wirst ständig Strings benutzen.
Früher oder später willst du ein doppeltes Anführungszeichen in einem String haben, und der
naheliegende Weg funktioniert nicht: Das zweite Anführungszeichen beendet den String zu früh, und
du bekommst denselben Fehler `unfinished string`, den du am Ende dieser Lektion kennenlernst. Es
gibt zwei Wege drumherum, und es lohnt sich, beide zu kennen.
[source,lua]
----
overlayPrint(2, 2, "She said \"hello\" to me.")
overlayPrint(2, 4, 'She said "hello" to me.')
----
Der erste setzt einen Backslash vor jedes Anführungszeichen, das zum Text gehört. Der Backslash
sagt „das nächste Zeichen gehört zum String, es ist nicht sein Ende“, und das Paar zusammen heißt
*Escape-Sequenz*. Der zweite benutzt einfache Anführungszeichen, um die Enden des Strings zu
markieren, und damit bleiben doppelte Anführungszeichen frei für gewöhnlichen Text. Lua nimmt beide
Arten von Anführungszeichen, solange der String mit derselben Art endet, mit der er angefangen hat.
Beide Zeilen geben genau dasselbe aus. Nimm, was leichter zu lesen ist, und das sind meistens die
einfachen Anführungszeichen, wenn der Text voller doppelter ist.
Die beiden Zahlen sind keine Pixel. `overlayPrint` ist der eigene schlichte Text der Engine, und
er zählt in Zeichenzellen: `(0, 0)` ist ganz oben links in der Ecke, `(1, 0)` ist einen Buchstaben
weiter rechts und `(0, 1)` eine Zeile tiefer. `(2, 2)` ist also zwei Buchstaben nach rechts und
zwei Zeilen nach unten. Andere Arten, Text zu zeichnen, zählen sehr wohl in Pixeln, und die lernst
du in Lektion neunzehn kennen.
[source,lua]
----
return OVERLAY_UPDATED
----
`return` gibt eine Antwort an den zurück, der die Funktion aufgerufen hat. Singe stellt deinem
`onOverlayUpdate` bei jedem Aufruf eine Frage: Hast du etwas geändert? `OVERLAY_UPDATED` heißt
ja, also bring es auf den Bildschirm.
`OVERLAY_UPDATED` steht nicht in Anführungszeichen, weil es kein Text ist. Es ist ein Name, den
Singe schon einem Wert gegeben hat, damit du etwas schreiben kannst, das man lesen kann, statt
einer Zahl, die du dir merken müsstest.
[source,lua]
----
end
----
Das passende Ende der `function`. Jede `function` hat genau eins, und es zu vergessen ist der
häufigste Fehler überhaupt.
[#_try_it]
=== Probier es aus
Ändere immer nur eine Sache, speichere und starte es noch einmal. Dieser Kreislauf -- ändern,
starten, hinsehen -- ist die ganze Arbeit.
. *Verschieb den Text.* Ändere `overlayPrint(2, 2, "Hello!")` in
`overlayPrint(10, 5, "Hello!")`. Dann probier `(0, 0)`. Dann probier `(200, 2)` und finde
heraus, warum er verschwunden ist.
. *Sag etwas anderes.* Schreib deinen eigenen Namen zwischen die Anführungszeichen.
. *Sag zwei Dinge.* Füg unter der ersten eine zweite Zeile mit `overlayPrint` ein, mit einer
anderen Zeilennummer und anderem Text. Nichts hindert dich daran, so viele zu haben, wie du
willst.
. *Nimm das Löschen raus.* Lösch die Zeile `overlayClear()` und starte es. Nichts ändert sich,
weil sich auf deinem Bildschirm noch nichts bewegt. Setz sie trotzdem wieder ein. In Lektion
zwei wird sie enorm wichtig, und jetzt ist ein guter Moment, um zu sehen, dass manche Fehler
warten, bevor sie zubeißen.
[#_break_it_on_purpose]
=== Mach es absichtlich kaputt
Anfänger verbringen mehr Zeit damit, Fehlermeldungen zu lesen, als Bücher übers Programmieren,
also bringen wir die erste gleich hinter uns.
Lösch das schließende Anführungszeichen nach `Hello!`, sodass die Zeile
`overlayPrint(2, 2, "Hello!)` lautet, und starte es. Singe weigert sich zu starten und sagt:
----
Error running script: hello/hello.singe:3: unfinished string near '"Hello!)'
----
Lies die Meldung von links. `hello/hello.singe` ist die Datei: der Ordner, dann das Skript
darin. `3` ist die Zeile. Der Rest ist, was
schiefgegangen ist, in diesem Fall ein Stück Text, das geöffnet und nie geschlossen wurde. Geh in
Zeile drei, setz das Anführungszeichen wieder ein, und es läuft.
Fast jeder Fehler, den du je sehen wirst, hat diese Form: eine Datei, eine Zeile und eine
Beschwerde. Die Beschwerde ist manchmal für jemanden geschrieben, der Lua schon kann, aber Datei
und Zeile stimmen immer, und in neun von zehn Fällen reicht die Zeile.
[#_stop_restarting_it]
=== Hör auf, es neu zu starten
Du hast Singe jetzt fünf- oder sechsmal von Hand gestartet. Lass das. Starte es stattdessen so:
----
Singe -R hello
----
`-R` sagt Singe, dass es dein Skript beobachten soll. Speichere eine Änderung in deinem Editor, und
das Spiel startet sich einen Moment später selbst neu, mit deiner Änderung darin, ohne das Fenster
zu schließen. Speicherst du einen Fehler, wird der Fehler ausgegeben, und das Fenster bleibt leer,
bis du eine Korrektur speicherst.
Benutze `-R` für den Rest dieses Buchs.
[#_what_you_learned]
=== Was du gelernt hast
* Ein Programm ist eine Datei mit Anweisungen, die der Reihe nach passieren, von oben nach unten.
* Eine `function` fasst Anweisungen unter einem Namen zusammen und hört bei ihrem `end` auf.
* `onOverlayUpdate` ist ein Name, nach dem Singe sucht und den es viele Male pro Sekunde aufruft,
und dort kommt alles hin, was du zeichnest.
* Eine Funktion aufrufen heißt, ihren Namen und Klammern zu schreiben. Alles in den Klammern ist
ein Argument.
* Eine Funktion, die die Engine für dich aufruft, statt dass du sie selbst aufrufst, ist ein
Callback. `onOverlayUpdate` ist einer.
* Text in doppelten Anführungszeichen ist ein String.
* Lösch den Bildschirm, bevor du darauf zeichnest.
* Ein Fehler nennt dir die Datei und die Zeile. Fang dort an.
[#_next_time]
=== Beim nächsten Mal
Dein `Hello!` sitzt, wo du es hingesetzt hast, und bewegt sich nie. Damit es sich bewegt, brauchst
du einen Ort, an dem eine Zahl liegt, die sich ändert -- eine *Variable*. Darum geht es in der
ganzen Lektion zwei.