A team of parts
Ein Team aus Teilen
The game is about 200 small files. Nobody could keep all of them in their head at once. So they are sorted into a few parts, and every part has one job, like the people in a team.
Das Spiel besteht aus etwa 200 kleinen Dateien. Niemand könnte die alle gleichzeitig im Kopf behalten. Darum sind sie in ein paar Teile sortiert, und jeder Teil hat eine Aufgabe, wie die Leute in einem Team.
An arrow from one part to another means: "I borrow code from you". This picture is not drawn by hand: the page reads the game's code right now and counts. When the game changes, the picture changes with it.
Ein Pfeil von einem Teil zum anderen heißt: "Ich leihe mir Code von dir." Dieses Bild ist nicht von Hand gezeichnet: Die Seite liest gerade jetzt den Code des Spiels und zählt. Wenn sich das Spiel ändert, ändert sich das Bild mit.
The conductor
Der Dirigent
In an orchestra, every musician knows their own part. The conductor makes sure they play together, at the right moment.
In einem Orchester kennt jeder Musiker seine eigene Stimme. Der Dirigent sorgt dafür, dass alle zusammen spielen, im richtigen Moment.
In Cube Crawler, the conductor is one short file: src/main.js. It doesn't know how to move a spider or paint a tree. It only knows who to ask, and in which order. About 60 times a second it goes through its list:
In Cube Crawler ist der Dirigent eine kurze Datei: src/main.js. Sie weiß nicht, wie man eine Spinne bewegt oder einen Baum malt. Sie weiß nur, wen sie fragen muss, und in welcher Reihenfolge. Ungefähr 60-mal pro Sekunde geht sie ihre Liste durch:
- game/: "Move the hero." (It asks physics/ about walls and floors.)
- game/: "Beweg den Helden." (Er fragt physics/ nach Wänden und Böden.)
- game/: "Let the monsters think and move. Did a sword hit?"
- game/: "Lass die Monster denken und sich bewegen. Hat ein Schwert getroffen?"
- render/: "Pose the hero's arms and legs, move the sparks, wave the grass."
- render/: "Bring Arme und Beine des Helden in Pose, beweg die Funken, lass das Gras wehen."
- audio/: "Play the footsteps."
- audio/: "Spiel die Schritte."
- game/: "Move the camera, cut a hole in the roof."
- game/: "Beweg die Kamera, schneide ein Loch ins Dach."
- audio/: "Is the music still right?"
- audio/: "Passt die Musik noch?"
- render/: "Now paint the picture!"
- render/: "Und jetzt mal das Bild!"
The order matters. The camera must move after the hero, or it would always be one step behind.
Die Reihenfolge ist wichtig. Die Kamera muss sich nach dem Helden bewegen, sonst wäre sie immer einen Schritt zu spät.
The heartbeat, slide by slide Der Herzschlag, Folie für FolieRules and pictures are kept apart
Regeln und Bilder sind getrennt
One of the smartest ideas in this game: the rules don't know anything about the pictures.
Eine der klügsten Ideen in diesem Spiel: Die Regeln wissen nichts über die Bilder.
The file src/core/combat.js decides if your sword hits a spider and how much it hurts. It is just math.
A different file, src/game/juice.js, adds the sparks, the damage number and the "thwack" sound.
Die Datei src/core/combat.js entscheidet, ob dein Schwert eine Spinne trifft und wie sehr es wehtut. Das ist nur Mathe.
Eine andere Datei, src/game/juice.js, fügt die Funken, die Schadenszahl und das "Zack"-Geräusch hinzu.
Why is that smart?
Warum ist das klug?
- The rules can be tested without a screen. A test can check "does the Old Sword need two hits for a spider?" in a split second.
- Die Regeln kann man testen, ganz ohne Bildschirm. Ein Test kann in einem Sekundenbruchteil prüfen: "Braucht das Alte Schwert zwei Treffer für eine Spinne?"
- You can change how things look without breaking how they work.
- Du kannst ändern, wie Dinge aussehen, ohne kaputt zu machen, wie sie funktionieren.
- The world builder can run in the background, without drawing anything.
- Der Weltbauer kann im Hintergrund laufen, ohne etwas zu malen.
That is how the "juice" file starts. It promises: you could delete all the sparks and the game would still play the same.
So fängt die "Juice"-Datei an. Sie verspricht: Man könnte alle Funken löschen, und das Spiel würde sich genauso spielen.
Juice: why hits feel good Juice: Warum Treffer sich gut anfühlenWho knows whom
Wer wen kennt
Look at the arrows in the picture of the parts again. Most of them point down: from the conductor to the play, from the play to the body, the painter and the band, and from all of them to the rule book at the bottom.
Schau dir die Pfeile im Bild der Teile noch mal an. Die meisten zeigen nach unten: vom Dirigenten zum Spiel, vom Spiel zum Körper, zum Maler und zur Band, und von allen zum Regelbuch ganz unten.
The rule book (core/) borrows from almost nobody. That is on purpose. A part that needs nothing else is easy to understand, easy to test and safe to use from anywhere: the game, the worker, the tests and the guide you're reading all use it.
Das Regelbuch (core/) leiht sich von fast niemandem etwas. Das ist Absicht. Ein Teil, der nichts anderes braucht, ist leicht zu verstehen, leicht zu testen und überall sicher zu benutzen: Das Spiel, der Worker, die Tests und dieser Führer, den du gerade liest, benutzen es alle.
The higher up a part is, the more it knows about the others, and the more can go wrong when something changes. That's why the top parts are kept thin: main.js is only about a hundred lines long.
Je weiter oben ein Teil ist, desto mehr weiß er über die anderen, und desto mehr kann schiefgehen, wenn sich etwas ändert. Darum sind die oberen Teile schlank: main.js hat nur ungefähr hundert Zeilen.
Arrows that point up
Pfeile, die nach oben zeigen
A few arrows go the other way. The body and the painter peek into game/, but almost always into the same file: the shared notebook, game/state.js. Mostly they just read things there, like where the hero is.
Ein paar Pfeile gehen andersherum. Der Körper und der Maler schauen in game/ hinein, aber fast immer in dieselbe Datei: das gemeinsame Notizbuch, game/state.js. Meistens lesen sie dort nur etwas nach, zum Beispiel, wo der Held ist.
Real programs are never perfectly tidy. The trick is to know where the untidy places are, and keep them few.
Echte Programme sind nie perfekt aufgeräumt. Der Trick ist, zu wissen, wo die unordentlichen Stellen sind, und davon nur wenige zu haben.
The shared notebook Das gemeinsame NotizbuchThe shared notebook
Das gemeinsame Notizbuch
The parts need to know the same things: where is the hero? How much health is left? Which cube are we in?
Die Teile müssen dieselben Dinge wissen: Wo ist der Held? Wie viel Gesundheit ist noch übrig? In welchem Würfel sind wir?
So there is one notebook that everybody can look into: game/state.js. It holds two big objects:
Darum gibt es ein Notizbuch, in das alle hineinschauen können: game/state.js. Darin stehen zwei große Objekte:
player: the hero. Where it stands (x,y,z), how fast it moves (vx,vy,vz), its health, its sword, its bag...player: der Held. Wo er steht (x,y,z), wie schnell er sich bewegt (vx,vy,vz), seine Gesundheit, sein Schwert, seine Tasche...state: everything else about this moment of the game: the map of the cube you're in, the time, the seed, which guardians you have beaten.state: alles andere über diesen Moment im Spiel: die Karte des Würfels, in dem du bist, die Zeit, der Seed, welche Wächter du schon besiegt hast.
The body writes the hero's position into the notebook. The painter reads it to draw the hero there. The camera reads it to follow. Nobody has to call anybody: they all look at the same page.
Der Körper schreibt die Position des Helden ins Notizbuch. Der Maler liest sie, um den Helden dort zu malen. Die Kamera liest sie, um ihm zu folgen. Niemand muss jemanden anrufen: Alle schauen auf dieselbe Seite.
Try it: a box called "map"
Probier es: eine Kiste namens "map"
The most important thing the parts hand to each other is a cube's map. The cube factory fills it, and then many parts read it: the body asks it how high the ground is, the painter turns it into triangles, the monsters look in it for floors to walk on, the minimap draws it.
Das Wichtigste, was sich die Teile gegenseitig geben, ist die Karte (map) eines Würfels. Die Würfelfabrik füllt sie, und dann lesen viele Teile darin: Der Körper fragt sie, wie hoch der Boden ist, der Maler macht Dreiecke daraus, die Monster suchen darin nach Böden zum Laufen, die Minikarte malt sie.
Here the real cube factory builds a cube for you. Open the box and look inside. Under every thing it says which parts of the game use it (the page searches the game's code for it).
Hier baut die echte Würfelfabrik einen Würfel für dich. Mach die Kiste auf und schau hinein. Unter jedem Ding steht, welche Teile des Spiels es benutzen (die Seite sucht dafür im Code des Spiels).
Two workers at the same time
Zwei Arbeiter gleichzeitig
Building a cube can take a moment. If the game did it in between two pictures, everything would freeze. You would notice that!
Einen Würfel zu bauen kann einen Moment dauern. Wenn das Spiel das zwischen zwei Bildern machen würde, würde alles einfrieren. Das würdest du merken!
So the browser gives the game a second worker, called a web worker. It runs at the same time as the game, like a cook in the kitchen while the waiter serves.
Darum gibt der Browser dem Spiel einen zweiten Arbeiter, einen Web Worker. Er läuft gleichzeitig mit dem Spiel, wie ein Koch in der Küche, während der Kellner bedient.
- The main thread plays and draws: the hero, the monsters, the picture.
- Der Haupt-Thread spielt und malt: der Held, die Monster, das Bild.
- The worker plans the world and builds cubes, and even their triangles.
- Der Worker plant die Welt und baut Würfel, sogar ihre Dreiecke.
They talk in letters
Sie reden in Briefen
The two can't look into each other's notebooks. They send messages, like letters: the game writes "please make cube -3,-1,-3", and some time later a letter comes back with the map inside.
Die beiden können nicht in das Notizbuch des anderen schauen. Sie schicken sich Nachrichten, wie Briefe: Das Spiel schreibt "bitte bau Würfel -3,-1,-3", und etwas später kommt ein Brief mit der Karte darin zurück.
The game doesn't wait at the mailbox. As soon as you enter a cube, it orders the cubes behind its portals. By the time you walk through, the letter is usually already there.
Das Spiel wartet nicht am Briefkasten. Sobald du einen Würfel betrittst, bestellt es die Würfel hinter seinen Portalen. Wenn du hindurchgehst, ist der Brief meistens schon da.
That is why the rule book must not need a screen: the worker doesn't have one.
Darum darf das Regelbuch keinen Bildschirm brauchen: Der Worker hat keinen.
Try it: follow a cube, from order to screen
Probier es: Folge einem Würfel, von der Bestellung bis zum Bildschirm
- You enter a cube. The game (
game/flow.js) orders the cubes behind its portals, just in case. - Du betrittst einen Würfel. Das Spiel (
game/flow.js) bestellt vorsichtshalber die Würfel hinter seinen Portalen. world/client.jswrites a letter to the worker: "please make this cube".world/client.jsschreibt dem Worker einen Brief: "Bitte bau diesen Würfel."- In the worker, the planner (
world/world.js) solves the puzzle for the cube's whole depth (only the first time it needs a cube from there), and fixes the walls the cube shares with its neighbours. - Im Worker löst der Planer (
world/world.js) das Puzzle für die ganze Tiefe des Würfels (nur beim ersten Würfel, den er von dort braucht) und legt die Wände fest, die der Würfel mit seinen Nachbarn teilt. - It looks up the theme of the depth: how hilly, how much water, which colours.
- Er schaut das Thema der Tiefe nach: wie hügelig, wie viel Wasser, welche Farben.
- The cube factory (
cubegen/) builds the cube step by step, and checks it. Can't get through? Throw it away, try again. - Die Würfelfabrik (
cubegen/) baut den Würfel Schritt für Schritt und prüft ihn. Man kommt nicht durch? Wegwerfen, noch mal. - All along, it uses the rule book: how big a cube is, how high a step is, its own dice.
- Dabei benutzt sie die ganze Zeit das Regelbuch: wie groß ein Würfel ist, wie hoch eine Stufe ist, ihre eigenen Würfel zum Würfeln.
- Still in the worker, one file of the painter (
render/cubegeo.js) turns the cube into triangles. - Noch im Worker macht eine Datei des Malers (
render/cubegeo.js) aus dem Würfel Dreiecke. - The worker sends a letter back: the map and the triangles.
world/client.jskeeps them. - Der Worker schickt einen Brief zurück: die Karte und die Dreiecke.
world/client.jshebt sie auf. - You walk through the portal. The game puts the map into the notebook.
- Du gehst durch das Portal. Das Spiel legt die Karte ins Notizbuch.
- The painter builds the 3D scene: ground, water, trees, lights.
- Der Maler baut die 3D-Szene: Boden, Wasser, Bäume, Lichter.
- The monsters come in. They will walk on the floors in the map.
- Die Monster kommen herein. Sie werden auf den Böden in der Karte laufen.
- From now on, the body asks the map every frame: how high is the ground right here?
- Ab jetzt fragt der Körper die Karte in jedem Bild: Wie hoch ist der Boden genau hier?
Try it: follow one sword hit
Probier es: Folge einem Schwerthieb
- You click on a spider.
game/input.jshears the click, andgame/orders.jsmakes it an order: "go there and attack". - Du klickst auf eine Spinne.
game/input.jshört den Klick, undgame/orders.jsmacht daraus einen Befehl: "Geh hin und greif an." - The hero walks there. The body knows which floors connect, so it goes around walls.
- Der Held läuft hin. Der Körper weiß, welche Böden verbunden sind, also geht er um Wände herum.
- Close enough!
game/sword.jsasks for a swing... - Nah genug!
game/sword.jsbittet um einen Hieb... - ...and the rule book (
core/combat.js) runs it: wind-up, the moment the blade can hit, recovery. - ...und das Regelbuch (
core/combat.js) führt ihn aus: Ausholen, der Moment, in dem die Klinge treffen kann, Erholen. - While the blade can hit, the game checks every monster, every frame:
- Solange die Klinge treffen kann, prüft das Spiel in jedem Bild jedes Monster:
- Is it inside the sword's arc? (a rule)
- Ist es im Bogen des Schwerts? (eine Regel)
- Is there a wall in between? (the body knows)
- Ist eine Wand dazwischen? (der Körper weiß es)
- Hit! The rule book works out the damage, maybe a critical hit, and takes it off the spider's health. Just numbers so far.
- Treffer! Das Regelbuch rechnet den Schaden aus, vielleicht einen kritischen Treffer, und zieht ihn von der Gesundheit der Spinne ab. Bis jetzt nur Zahlen.
- Now the juice:
game/juice.jsasks the painter for sparks and a flying damage number... - Jetzt kommt der Juice:
game/juice.jsbittet den Maler um Funken und eine fliegende Schadenszahl... - ...and the band for a "thwack".
- ...und die Band um ein "Zack".
- Health at zero?
game/enemies.jsgives you experience and drops the loot. - Gesundheit bei null?
game/enemies.jsgibt dir Erfahrung und lässt die Beute fallen. - Which loot? The rule book's weapon machine (
core/gear/) decides. - Welche Beute? Die Waffenmaschine im Regelbuch (
core/gear/) entscheidet.
With a bow, crossbow or staff the middle is different: at the moment of the hit, an arrow, a bolt or a spell flies off, and every frame the game checks whether it touches a monster or a wall.
Mit einem Bogen, einer Armbrust oder einem Stab ist die Mitte anders: Im Moment des Treffers fliegt ein Pfeil, ein Bolzen oder ein Zauber los, und in jedem Bild prüft das Spiel, ob er ein Monster oder eine Wand berührt.
One click, five parts, and a dozen files. Each one only does its own small job.
Ein Klick, fünf Teile und ein Dutzend Dateien. Jede macht nur ihre eigene kleine Aufgabe.
Made before you play, made while you play
Vor dem Spielen gemacht, beim Spielen gemacht
Before you play
Vor dem Spielen
Some things are made once, by the people who build the game, and saved as files:
Manche Dinge werden einmal gemacht, von den Leuten, die das Spiel bauen, und als Dateien gespeichert:
- Models. Scripts in
blender/build the hero, the monsters, swords and houses in Blender and save them intoassets/. The painter loads them from there. - Modelle. Skripte in
blender/bauen den Helden, die Monster, Schwerter und Häuser in Blender und speichern sie inassets/. Der Maler lädt sie von dort. - Item pictures for the inventory, rendered by the same scripts.
- Bilder von Gegenständen fürs Inventar, von denselben Skripten gerendert.
- Songs. Written as text files in
music/. The band reads them and plays them. - Lieder. Als Textdateien in
music/geschrieben. Die Band liest sie und spielt sie.
While you play
Beim Spielen
Everything else is made by code, right when it's needed:
Alles andere macht der Code, genau dann, wenn es gebraucht wird:
- Every cube, by the planner and the cube factory.
- Jeder Würfel, vom Planer und der Würfelfabrik.
- Every weapon that drops, by the weapon machine.
- Jede Waffe, die fällt, von der Waffenmaschine.
- Every sound: no sound files at all, only recipes.
- Jedes Geräusch: überhaupt keine Sounddateien, nur Rezepte.
- The music itself: the songs are only notes, the instruments are made from math.
- Die Musik selbst: Die Lieder sind nur Noten, die Instrumente entstehen aus Mathe.
All the code that invents the world is smaller than the model of a single fire cat. Rules take much less space than the things they make.
Der ganze Code, der die Welt erfindet, ist kleiner als das Modell einer einzigen Feuerkatze. Regeln brauchen viel weniger Platz als die Dinge, die sie machen.
And then there are parts that are not in the game at all: tests/ and tools/. They borrow the game's parts to check and measure them.
Und dann gibt es Teile, die gar nicht im Spiel sind: tests/ und tools/. Sie leihen sich die Teile des Spiels, um sie zu prüfen und zu messen.
The real code: where it all starts
Der echte Code: wo alles anfängt
// Entry point: load the first cube and run the frame loop.
import { renderer, scene, camera } from './render/scene.js';
import { loadCube } from './game/flow.js';
import { updatePlayer } from './game/update.js';
import { updateEnemies } from './game/enemies.js';
// ... about 50 more imports ...
function frame() {
// ... listen, think, draw (see the next room) ...
renderer.render(scene, camera);
requestAnimationFrame(frame);
}
loadCube();
setStatus('Welcome to town. Follow the path through the grove to leave.');
frame();
import lines borrow functions from other files. ./render/scene.js means "the file scene.js in the folder render next to me". Every arrow in the picture of the parts is made of lines like these.
import-Zeilen leihen sich Funktionen aus anderen Dateien. ./render/scene.js heißt: "die Datei scene.js im Ordner render neben mir". Jeder Pfeil im Bild der Teile besteht aus solchen Zeilen.
function frame() is the conductor's list. At the end it asks the browser: "call frame again before the next picture". That is how it runs forever.
function frame() ist die Liste des Dirigenten. Am Ende bittet sie den Browser: "Ruf frame vor dem nächsten Bild nochmal auf." So läuft sie für immer.
The last three lines run once: load the town cube, show the welcome message, start the heartbeat.
Die letzten drei Zeilen laufen nur einmal: den Stadtwürfel laden, die Begrüßung zeigen, den Herzschlag starten.
The whole frame function, explained Die ganze frame-Funktion, erklärtThe real code: the worker's mailbox
Der echte Code: der Briefkasten des Workers
This is the whole worker. It is short, because the real work happens in the files it imports.
Das ist der ganze Worker. Er ist kurz, weil die echte Arbeit in den Dateien passiert, die er importiert.
onmessageis the mailbox. Every letter from the game arrives here, asdata.onmessageist der Briefkasten. Jeder Brief vom Spiel kommt hier an, alsdata.- A letter of type
'init'says: "here is the seed, start a new world". - Ein Brief vom Typ
'init'sagt: "Hier ist der Seed, fang eine neue Welt an." - A letter of type
'cube'says: "make this cube". The worker builds it, turns it into triangles, and answers withpostMessage: the letter back. - Ein Brief vom Typ
'cube'sagt: "Bau diesen Würfel." Der Worker baut ihn, macht Dreiecke daraus und antwortet mitpostMessage: dem Brief zurück. - If building fails, the answer is a letter of type
'error'instead, so the game is never left waiting forever. - Wenn das Bauen schiefgeht, ist die Antwort stattdessen ein Brief vom Typ
'error', damit das Spiel nie ewig wartet.
The big picture
Das große Bild
If you remember five things from this room, make it these:
Wenn du dir aus diesem Raum fünf Dinge merkst, dann diese:
- One job per part. The planner plans, the painter paints, the rule book knows the rules.
- Eine Aufgabe pro Teil. Der Planer plant, der Maler malt, das Regelbuch kennt die Regeln.
- A conductor asks them in the right order, 60 times a second.
- Ein Dirigent fragt sie in der richtigen Reihenfolge, 60-mal pro Sekunde.
- Arrows point down. The rules at the bottom need nobody, so everybody can use them.
- Pfeile zeigen nach unten. Die Regeln ganz unten brauchen niemanden, darum kann jeder sie benutzen.
- Shared things are written down: the notebook, and the map in its box.
- Was alle brauchen, wird aufgeschrieben: das Notizbuch und die Karte in ihrer Kiste.
- Slow work goes to the worker, so the picture never freezes.
- Langsame Arbeit geht an den Worker, damit das Bild nie einfriert.
The next room teaches you to read the code itself. The rooms after it each visit one of the parts. You can always come back here to see where you are.
Im nächsten Raum lernst du, den Code selbst zu lesen. Die Räume danach besuchen jeweils einen der Teile. Du kannst immer hierher zurückkommen, um zu sehen, wo du bist.