[#_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.