Code is just text

Code ist einfach Text

Every file of the game is plain text, the same letters you type in a message. It's written in a language the computer understands, called JavaScript.

Jede Datei des Spiels ist einfacher Text, dieselben Buchstaben, die du in einer Nachricht tippst. Er ist in einer Sprache geschrieben, die der Computer versteht: JavaScript.

The computer reads it from top to bottom, and does exactly what it says. Here is the start of a real file of the game. The colours help you read it:

Der Computer liest ihn von oben nach unten und macht genau, was dasteht. Hier ist der Anfang einer echten Datei des Spiels. Die Farben helfen dir beim Lesen:

  • grey: comments. Everything after // is a note for people. The computer skips it.
  • grau: Kommentare. Alles nach // ist eine Notiz für Menschen. Der Computer überspringt sie.
  • orange: words of the language itself, like const, function, if, return. There are only a few dozen.
  • orange: Wörter der Sprache selbst, wie const, function, if, return. Davon gibt es nur ein paar Dutzend.
  • blue: numbers. green: text in quotes.
  • blau: Zahlen. grün: Text in Anführungszeichen.
  • white: names that the game's makers made up, like CAST_TIME.
  • weiß: Namen, die sich die Macher des Spiels ausgedacht haben, wie CAST_TIME.

      

That is the town portal scroll: you stand still for 5 seconds to open it, then stand in it for 1 second to go through.

Das ist die Stadtportal-Schriftrolle: Du stehst 5 Sekunden still, um es zu öffnen, und dann 1 Sekunde darin, um hindurchzugehen.

English Code and its comments are written in English, almost everywhere in the world, even by people who speak other languages.
Englisch Code und Kommentare sind auf Englisch, fast überall auf der Welt. Beim Code-Lesen lernst du also nebenbei auch ein paar englische Wörter.

Names for values

Namen für Werte

Most lines of code give a name to a value, so the rest of the game can use the name. Such a name is called a variable.

Die meisten Codezeilen geben einem Wert einen Namen, damit der Rest des Spiels den Namen benutzen kann. So ein Name heißt Variable.


      
  • const means: this name is fixed. N is 16, forever. A cube is 16 cells wide.
  • const heißt: Dieser Name steht fest. N ist 16, für immer. Ein Würfel ist 16 Zellen breit.
  • = does not mean "is equal", like in maths. It means "put this value into this name".
  • = heißt nicht "ist gleich" wie in Mathe. Es heißt: "Leg diesen Wert in diesen Namen."
  • export means: other files may borrow it.
  • export heißt: Andere Dateien dürfen ihn sich leihen.
  • Numbers use a dot: 2.8, not 2,8.
  • Zahlen haben einen Punkt statt eines Kommas: 2.8, nicht 2,8.

Some values change while you play. Those are made with let. The music remembers its mood like this:

Manche Werte ändern sich beim Spielen. Die macht man mit let. Die Musik merkt sich ihre Stimmung so:


      

Later, when a fight starts, another line puts new text into mood, like 'fight'. Text is always in quotes, so the computer knows it isn't a name.

Später, wenn ein Kampf anfängt, legt eine andere Zeile neuen Text in mood, zum Beispiel 'fight'. Text steht immer in Anführungszeichen, damit der Computer weiß, dass es kein Name ist.

Why names? If the run speed were written as 2.8 in twenty places, changing it would mean finding all twenty. With a name, you change one line.
Warum Namen? Wenn das Renntempo an zwanzig Stellen als 2.8 stünde, müsste man zum Ändern alle zwanzig finden. Mit einem Namen änderst du eine Zeile.

Things with parts: objects

Dinge mit Teilen: Objekte

A spider has many numbers: health, damage, speed, size... Instead of fifty loose names, they are packed into one object: a value with named parts, written between curly brackets { }.

Eine Spinne hat viele Zahlen: Gesundheit, Schaden, Tempo, Größe... Statt fünfzig einzelner Namen werden sie in ein Objekt gepackt: einen Wert mit benannten Teilen, zwischen geschweiften Klammern { }.

Each part is name: value, with commas in between. To read one part, write the object, a dot, and the part's name:

Jeder Teil ist Name: Wert, mit Kommas dazwischen. Um einen Teil zu lesen, schreibst du das Objekt, einen Punkt und den Namen des Teils:

  • SPIDER.hp is 32: its health.
  • SPIDER.hp ist 32: ihre Gesundheit.
  • SPIDER.aggro is 3: how close you can come before it notices you.
  • SPIDER.aggro ist 3: wie nah du kommen kannst, bevor sie dich bemerkt.
  • SPIDER.label is 'Spider': the name you see in the game.
  • SPIDER.label ist 'Spider': der Name, den du im Spiel siehst.

Object.freeze(...) locks the object, so nothing can change a spider's numbers by mistake while the game runs.

Object.freeze(...) sperrt das Objekt ab, damit nichts aus Versehen die Zahlen einer Spinne ändert, während das Spiel läuft.

A monster is a list of numbers Ein Monster ist eine Liste von Zahlen

  

Try it: functions are little machines

Probier es: Funktionen sind kleine Maschinen

A function is a machine with a name. You put something in, it does its work, and something comes out.

Eine Funktion ist eine Maschine mit einem Namen. Du steckst etwas hinein, sie macht ihre Arbeit, und etwas kommt heraus.


      

Read it like this: "maxHealth is a machine. Give it a level, and => out comes 100, plus 10 for every level above 1." (The numbers come from the object PLAYER.)

Lies es so: "maxHealth ist eine Maschine. Gib ihr ein level, und => heraus kommt 100, plus 10 für jede Stufe über 1." (Die Zahlen kommen aus dem Objekt PLAYER.)

To use a machine, write its name and put the input in round brackets: maxHealth(5). That's called calling the function.

Um eine Maschine zu benutzen, schreibst du ihren Namen und die Eingabe in runde Klammern: maxHealth(5). Das nennt man die Funktion aufrufen.

Bigger machines are written with function name(input) { ... }, and say what comes out with return. Same idea.

Größere Maschinen schreibt man mit function name(eingabe) { ... }, und sie sagen mit return, was herauskommt. Dieselbe Idee.

Lists

Listen

A list holds several values in a row, between square brackets [ ]:

Eine Liste hält mehrere Werte hintereinander, zwischen eckigen Klammern [ ]:


      
  • To get one thing out, write its position in square brackets. But careful: counting starts at 0. FLUIDS[0] is WATER, FLUIDS[2] is ACID.
  • Um ein Ding herauszuholen, schreibst du seine Position in eckige Klammern. Aber Vorsicht: Gezählt wird ab 0. FLUIDS[0] ist WATER, FLUIDS[2] ist ACID.
  • A list can hold lists. DIRS holds the four steps to a neighbouring cell: [1, 0] is one step along x.
  • Eine Liste kann Listen enthalten. DIRS enthält die vier Schritte zu einer Nachbarzelle: [1, 0] ist ein Schritt entlang x.
  • FLUIDS.length says how many things are in it: 3.
  • FLUIDS.length sagt, wie viele Dinge darin sind: 3.

And a list can hold objects. Here are the game's three coins:

Und eine Liste kann Objekte enthalten. Hier sind die drei Münzen des Spiels:


      

COINS[1].name is 'Silver': the thing at position 1, then its part called name.

COINS[1].name ist 'Silver': das Ding an Position 1, und davon der Teil namens name.

The last line runs a little machine (.map) on every coin to add a few more parts. You'll meet machines that work through lists on the loops slide.

Die letzte Zeile lässt eine kleine Maschine (.map) über jede Münze laufen, um ein paar Teile hinzuzufügen. Maschinen, die Listen abarbeiten, triffst du auf der Folie über Schleifen.

Doing maths

Rechnen

Computers are very good at maths. Code writes it almost like you do:

Computer können sehr gut rechnen. Code schreibt es fast so wie du:

a + b, a - bplus, minus plus, minus
a * btimes (there is no × key) mal (es gibt keine ×-Taste)
a / bdivided by geteilt durch
a ** 2a squared a hoch 2
a % bthe remainder: what is left over after dividing. 7 % 3 is 1. der Rest: was beim Teilen übrig bleibt. 7 % 3 ist 1.
Math.floor(x)round down: Math.floor(2.9) is 2 abrunden: Math.floor(2.9) ist 2
Math.min(a, b)the smaller one (Math.max: the bigger one) die kleinere (Math.max: die größere)

Your bag keeps all money as copper. To show it as gold, silver and copper, this machine splits it up:

Deine Tasche hebt alles Geld als Kupfer auf. Um es als Gold, Silber und Kupfer zu zeigen, teilt diese Maschine es auf:


      

With 1234 copper:

Mit 1234 Kupfer:

  • gold: Math.floor(1234 / 1000) = 1
  • Gold: Math.floor(1234 / 1000) = 1
  • silver: 1234 % 1000 is 234, / 10 rounded down = 23
  • Silber: 1234 % 1000 ist 234, / 10 abgerundet = 23
  • copper: 1234 % 10 = 4
  • Kupfer: 1234 % 10 = 4

So the bag shows 1g 23s 4c. Check it with the formatCoins machine on the slide before!

Also zeigt die Tasche 1g 23s 4c. Prüf es mit der formatCoins-Maschine auf der Folie davor!

Try it: making decisions with if

Probier es: Entscheidungen mit if

Games are full of decisions: did the sword hit? Is the spider close enough? Can you pay for that? Code decides with if:

Spiele sind voller Entscheidungen: Hat das Schwert getroffen? Ist die Spinne nah genug? Kannst du das bezahlen? Code entscheidet mit if (falls):

if (question) do this;

if (Frage) mach das;

The question goes in round brackets. If the answer is yes (true), the rest runs. If not (false), it is skipped. else can say what to do otherwise.

Die Frage steht in runden Klammern. Wenn die Antwort ja ist (true), läuft der Rest. Wenn nicht (false), wird er übersprungen. Mit else kann man sagen, was sonst passieren soll.

a < b, a > bless than, more than kleiner als, größer als
a <= bless than or the same kleiner oder gleich
a === bthe same? (three = signs, because one = means "put") gleich? (drei =-Zeichen, weil ein = "leg hinein" heißt)
!anot nicht
a && b, a || band, or und, oder

return leaves the function at once, with an answer. Nothing after it runs.

return verlässt die Funktion sofort, mit einer Antwort. Nichts danach läuft noch.

Doing it again: loops

Noch mal und noch mal: Schleifen

Every frame, the game has to look at every monster: is it dead? Then you get its experience and its loot. Nobody would write that out for each monster. A loop does it:

In jedem Bild muss das Spiel sich jedes Monster anschauen: Ist es tot? Dann bekommst du seine Erfahrung und seine Beute. Niemand würde das für jedes Monster einzeln hinschreiben. Eine Schleife macht das:

for (const e of list) {
  const reward = awardKill(player, state.run, e);
  if (reward) {
    xp += reward.xp; levels += reward.levels; killed++; dropLoot(e, reward.coins);
    if (e.guardianGate) unlocked = true;
  }
}

Read it as: "for each monster e of the list, do what's in the curly brackets". The first time round, e is the first monster, then the second, and so on, until the list is done.

Lies es so: "Für (for) jedes Monster e aus (of) der liste, mach, was in den geschweiften Klammern steht." Beim ersten Durchlauf ist e das erste Monster, dann das zweite, und so weiter, bis die Liste fertig ist.

xp += reward.xp is short for xp = xp + reward.xp: add to what's there. killed++ adds one.

xp += reward.xp ist kurz für xp = xp + reward.xp: zu dem dazuzählen, was schon da ist. killed++ zählt eins dazu.

Sometimes you just want to count. A guardian drops several weapons:

Manchmal willst du einfach zählen. Ein Wächter lässt mehrere Waffen fallen:

for (let i = 0; i < g.count; i++) out.push(rollWeapon(R, level, { ...g, favor }));

This one has three parts, separated by ;:

Diese hat drei Teile, getrennt durch ;:

  1. let i = 0: start counting at 0,
  2. let i = 0: bei 0 anfangen zu zählen,
  3. i < g.count: keep going while i is less than the number of weapons,
  4. i < g.count: weitermachen, solange i kleiner ist als die Zahl der Waffen,
  5. i++: after each round, add one.
  6. i++: nach jeder Runde eins dazuzählen.

Each round, out.push(...) rolls a new weapon and adds it to the end of the list out.

In jeder Runde würfelt out.push(...) eine neue Waffe und hängt sie hinten an die Liste out an.

{ ...g, favor } is a new object with everything from g in it, and also favor: the kind of weapon you fight with, so the machine rolls more of those.

{ ...g, favor } ist ein neues Objekt mit allem aus g darin und dazu favor: die Art Waffe, mit der du kämpfst, damit die Maschine mehr davon würfelt.

Borrowing from other files

Von anderen Dateien leihen

A file can only use what it made itself, or what it borrowed. The first lines of a file usually say what it borrows:

Eine Datei kann nur benutzen, was sie selbst gemacht hat, oder was sie sich geliehen hat. Die ersten Zeilen einer Datei sagen meistens, was sie sich leiht:

import { createInventory, addInstance, addItem, equipItem, assignBar, whole } from './inventory.js';
import { OLD_SWORD, TOWN_PORTAL, HEALTH_POTION } from './items.js';
import { fixedWeapon } from './gear/generate.js';

"From the file inventory.js next to me, borrow createInventory, addItem..." The other file must have put export in front of them, or they can't be borrowed.

"Aus der Datei inventory.js neben mir leih dir createInventory, addItem..." Die andere Datei muss export davorgeschrieben haben, sonst kann man sie nicht ausleihen.

That's how 200 small files become one game. Every arrow in the picture of the parts is made of lines like these.

So werden aus 200 kleinen Dateien ein Spiel. Jeder Pfeil im Bild der Teile besteht aus solchen Zeilen.

It also helps you find your way: if you wonder where OLD_SWORD comes from, the import line tells you: items.js.

Es hilft dir auch beim Zurechtfinden: Wenn du dich fragst, wo OLD_SWORD herkommt, sagt dir die Import-Zeile: items.js.

The picture of the parts Das Bild der Teile

The real code: a file you've never seen

Der echte Code: eine Datei, die du noch nie gesehen hast


    

This is a whole file of the game: the rules of the town portal. Here's how to read a file you don't know:

Das ist eine ganze Datei des Spiels: die Regeln des Stadtportals. So liest du eine Datei, die du nicht kennst:

  1. Read the comment at the top. It says what the file is for, and what it doesn't do: "no rendering, no game state".
  2. Lies den Kommentar oben. Er sagt, wofür die Datei da ist, und was sie nicht macht: "kein Malen, kein Spielzustand".
  3. Look at what it borrows. Nothing! No import lines: it's a rule file that needs no other part.
  4. Schau, was sie sich leiht. Nichts! Keine import-Zeilen: eine Regeldatei, die keinen anderen Teil braucht.
  5. Look at what it offers: everything with export. TRIGGER_RADIUS has none, so it's only for this file.
  6. Schau, was sie anbietet: alles mit export. TRIGGER_RADIUS hat keins, also ist es nur für diese Datei.
  7. Pick one function, read the comment above it, then its lines. townPadIn: "where is the open portal in this cube? null if there is none."
  8. Such dir eine Funktion aus, lies den Kommentar darüber, dann ihre Zeilen. townPadIn: "Wo ist das offene Portal in diesem Würfel? null, wenn es keins gibt."

New signs: ?. means "if there is one": run?.townPortal doesn't break when there is no run. null means "nothing".

Neue Zeichen: ?. heißt "falls es eins gibt": run?.townPortal geht nicht kaputt, wenn es kein run gibt. null heißt "nichts".

You don't need to understand every line. Programmers skip a lot, too, until they need it.

Du musst nicht jede Zeile verstehen. Programmierer überspringen auch viel, bis sie es brauchen.

The real code: one sword hit, line by line

Der echte Code: ein Schwerttreffer, Zeile für Zeile


    

This is the rule from the sword journey. You can read all of it now:

Das ist die Regel aus der Reise des Schwerthiebs. Du kannst sie jetzt ganz lesen:

  • roll = Math.random(): if nobody gives a roll, use a random number between 0 and 1.
  • roll = Math.random(): Wenn niemand ein roll mitgibt, nimm eine Zufallszahl zwischen 0 und 1.
  • if (!inSwordArc(p, enemy)) return false;: not in front of the blade? Then no hit. Stop.
  • if (!inSwordArc(p, enemy)) return false;: Nicht vor der Klinge? Dann kein Treffer. Stopp.
  • p.sword.hits.add(enemy): remember this monster, so one swing can't hit it twice.
  • p.sword.hits.add(enemy): Merk dir dieses Monster, damit ein Hieb es nicht zweimal trifft.
  • weaponHit(...): the rest is its own function, because arrows, bolts and spells use it too. p.sword.stats || SWORD: the weapon's numbers, or the Old Sword's if there are none.
  • weaponHit(...): Der Rest ist eine eigene Funktion, weil Pfeile, Bolzen und Zauber sie auch benutzen. p.sword.stats || SWORD: die Zahlen der Waffe, oder die des Alten Schwerts, wenn es keine gibt.
  • stats.crit ?? 0: the sword's chance of a critical hit, or 0 if it has none (?? means "if that's missing, use this").
  • stats.crit ?? 0: die Chance des Schwerts auf einen kritischen Treffer, oder 0, wenn es keine hat (?? heißt "wenn das fehlt, nimm das").
  • crit ? A : B: a short if. If crit is true, use A (multiply by 1.5 or more: bigger damage), otherwise B (multiply by 1: the same).
  • crit ? A : B: ein kurzes if. Wenn crit wahr ist, nimm A (mal 1,5 oder mehr: mehr Schaden), sonst B (mal 1: gleich viel).
  • Math.max(1, Math.round(...)): round to a whole number, but never less than 1. (share is 1 for a full hit; a spell's burst only does half to the monsters around it.)
  • Math.max(1, Math.round(...)): auf eine ganze Zahl runden, aber nie weniger als 1. (share ist 1 bei einem vollen Treffer; die Explosion eines Zaubers macht bei den Monstern drumherum nur die Hälfte.)
  • damageEnemy(...): another machine takes the health off.
  • damageEnemy(...): eine andere Maschine zieht die Gesundheit ab.
  • return { damage, crit }: the answer is a small object, so the game knows what number to show, and if it should be golden.
  • return { damage, crit }: Die Antwort ist ein kleines Objekt, damit das Spiel weiß, welche Zahl es zeigen soll und ob sie golden sein soll.
The whole journey of a sword hit Die ganze Reise eines Schwerthiebs

A few signs that unlock all code

Ein paar Zeichen, die jeden Code aufschließen

Almost every line of the game is made of these. Once you know them, you can read the code in every room of this guide:

Fast jede Zeile des Spiels besteht daraus. Wenn du sie kennst, kannst du den Code in jedem Raum dieses Führers lesen:

YOU SEE DU SIEHSTIT MEANS ES HEISST
// ...a note for people eine Notiz für Menschen
const name = valuea name for a value (let: one that can change) ein Name für einen Wert (let: einer, der sich ändern kann)
{ hp: 32, damage: 15 }an object: a thing with named parts; read one with a dot: SPIDER.hp ein Objekt: ein Ding mit benannten Teilen; lies einen mit einem Punkt: SPIDER.hp
[1, 2, 3]a list; list[0] is the first thing eine Liste; list[0] ist das erste Ding
x => ..., function f(x) { }a machine; use it with f(5) eine Maschine; benutze sie mit f(5)
if (...) ... else ...a decision eine Entscheidung
for (const e of list)do it for every thing in a list mach es für jedes Ding in einer Liste
import, exportborrow from another file, lend to other files aus einer anderen Datei leihen, an andere Dateien verleihen

Whenever a slide shows real code, try to read it before you read the explanation. You'll be surprised how much you understand.

Wenn eine Folie echten Code zeigt, versuch ihn zu lesen, bevor du die Erklärung liest. Du wirst staunen, wie viel du verstehst.