A flipbook that thinks

Ein Daumenkino, das denkt

Have you ever made a flipbook? You draw a stick figure on every page, a tiny bit further along. Flip fast, and it runs!

Hast du schon mal ein Daumenkino gemacht? Du malst auf jede Seite ein Strichmännchen, jedes ein kleines Stück weiter. Blätterst du schnell, rennt es!

A game works the same way. It draws a new picture about 60 times every second. Each picture is called a frame.

Ein Spiel funktioniert genauso. Es malt ungefähr 60 neue Bilder pro Sekunde. Jedes Bild heißt Frame.

But a game is a flipbook that draws its next page while you watch, and the page depends on what you do. Press a key, and the next page shows the hero a little bit further to the left.

Aber ein Spiel ist ein Daumenkino, das seine nächste Seite malt, während du zuschaust, und die Seite hängt davon ab, was du tust. Drück eine Taste, und auf der nächsten Seite steht der Held ein bisschen weiter links.

The code that makes one page, again and again, is called the game loop. It is the heartbeat of every game.

Der Code, der eine Seite macht, immer und immer wieder, heißt Spielschleife (Game Loop). Sie ist der Herzschlag jedes Spiels.

Every frame, three steps

Jedes Bild, drei Schritte

  1. Listen: what is the player doing right now?
  2. Hören: Was macht der Spieler gerade?
  3. Think: move everything a tiny bit, and check what happened (hits, falls, pickups).
  4. Denken: alles ein winziges Stück bewegen und prüfen, was passiert ist (Treffer, Stürze, Aufsammeln).
  5. Draw: paint the new picture.
  6. Malen: das neue Bild malen.

Then do it again. And again. Forever, until you close the game.

Dann wieder von vorn. Und wieder. Für immer, bis du das Spiel schließt.

Try it: slow the heart down

Probier es: Lass das Herz langsamer schlagen

This little runner has its own game loop. Pull the slider down to make fewer pictures per second, and watch the three steps light up. Click the picture to jump: the runner only notices your click at the next LISTEN.

Dieser kleine Läufer hat seine eigene Spielschleife. Zieh den Regler runter, damit weniger Bilder pro Sekunde gemalt werden, und schau, wie die drei Schritte aufleuchten. Klick ins Bild zum Springen: Der Läufer bemerkt deinen Klick erst beim nächsten HÖREN.

At 60 pictures per second it looks smooth. Below about 15 it starts to stutter, and at 2 it becomes a slideshow. That is why games care so much about being fast.

Bei 60 Bildern pro Sekunde sieht es flüssig aus. Unter etwa 15 fängt es an zu ruckeln, und bei 2 wird es eine Diashow. Darum ist es Spielen so wichtig, schnell zu sein.

The secret number: dt

Die geheime Zahl: dt

Computers are not perfectly steady. Sometimes a frame takes 16 milliseconds, sometimes 30, on an old laptop maybe 50.

Computer sind nicht ganz gleichmäßig. Manchmal dauert ein Bild 16 Millisekunden, manchmal 30, auf einem alten Laptop vielleicht 50.

If the hero moved "4 pixels every frame", it would run slower on a slow computer. Not fair!

Würde sich der Held "4 Pixel pro Bild" bewegen, wäre er auf einem langsamen Computer langsamer. Unfair!

So each frame, the game measures how much time passed since the last one. That time is called dt (for "delta time", the difference in time). Then:

Darum misst das Spiel bei jedem Bild, wie viel Zeit seit dem letzten vergangen ist. Diese Zeit heißt dt (für "Delta-Zeit", den Unterschied in der Zeit). Dann gilt:

distance = speed × dt Strecke = Tempo × dt

A slow frame has a bigger dt, so the hero takes a bigger step. Same speed on every computer.

Ein langsames Bild hat ein größeres dt, also macht der Held einen größeren Schritt. Gleiches Tempo auf jedem Computer.

Race them at 60 pictures per second: a tie. Now set 20 and restart.

Lass sie bei 60 Bildern pro Sekunde um die Wette laufen: unentschieden. Stell jetzt 20 ein und starte neu.

One tick of Cube Crawler

Ein Takt von Cube Crawler

Here is what the real game does in one frame, in order. The order matters!

Das macht das echte Spiel in einem Bild, in dieser Reihenfolge. Die Reihenfolge ist wichtig!

  1. Find out which monster is under the mouse.
  2. Herausfinden, welches Monster unter der Maus ist.
  3. Move the hero: keys, mouse orders, sword swings, jumping, ladders, portals.
  4. Den Helden bewegen: Tasten, Mausbefehle, Schwerthiebe, Springen, Leitern, Portale.
  5. Move the monsters: each one decides what to do and does it.
  6. Die Monster bewegen: Jedes entscheidet, was es tun will, und tut es.
  7. Pose the hero's body for this moment of the walk or swing animation.
  8. Den Körper des Helden für diesen Moment der Lauf- oder Schlaganimation hinstellen.
  9. Footsteps, sounds, sparks, floating damage numbers, loot.
  10. Schritte, Geräusche, Funken, schwebende Schadenszahlen, Beute.
  11. Update the bars and the inventory on the screen.
  12. Die Balken und das Inventar auf dem Bildschirm aktualisieren.
  1. Move the camera so it follows the hero.
  2. Die Kamera bewegen, damit sie dem Helden folgt.
  3. Cut away walls that hide the hero (needs the camera first!).
  4. Wände wegschneiden, die den Helden verdecken (dafür muss die Kamera schon stehen!).
  5. Pick the 8 lamps nearest to you to light the scene.
  6. Die 8 Lampen auswählen, die dir am nächsten sind, um die Szene zu beleuchten.
  7. Pick the music mood (calm, danger, fight, boss).
  8. Die Musikstimmung wählen (ruhig, Gefahr, Kampf, Boss).
  9. Draw everything. Alles malen.
  10. Ask the browser to call us again for the next frame.
  11. Den Browser bitten, uns fürs nächste Bild wieder aufzurufen.
Think Why must the camera move before the cut-away step? Because the cut-away looks for walls between the hero and the camera, so it needs to know where the camera is this frame.
Denk nach Warum muss sich die Kamera vor dem Wegschneiden bewegen? Weil das Wegschneiden nach Wänden zwischen Held und Kamera sucht. Dafür muss es wissen, wo die Kamera in diesem Bild ist.
See the real code Sieh dir den echten Code an

Pause, slow motion and hiccups

Pause, Zeitlupe und Schluckauf

Because everything moves by speed × dt, a few tricks become very easy:

Weil sich alles mit Tempo × dt bewegt, werden ein paar Tricks ganz einfach:

Pause

When you open the inventory, the game sets dt = 0. Everything moves by "speed × 0", which is nothing. The whole world freezes, but it still gets drawn.

Wenn du das Inventar öffnest, setzt das Spiel dt = 0. Alles bewegt sich um "Tempo × 0", also gar nicht. Die ganze Welt friert ein, wird aber weiter gemalt.

Hit pause

Trefferpause

When your sword hits, time runs at only 3% speed for about 0.05 seconds. You barely notice it, but it makes hits feel heavy and strong. Juice

Wenn dein Schwert trifft, läuft die Zeit für etwa 0,05 Sekunden nur mit 3% Tempo. Du merkst es kaum, aber Treffer fühlen sich dadurch schwer und stark an. Juice

Hiccups

Schluckauf

If the computer freezes for a whole second, a huge dt could make the hero fly through a wall. So dt is never allowed to be bigger than 1/30 of a second.

Wenn der Computer eine ganze Sekunde hängt, könnte ein riesiges dt den Helden durch eine Wand fliegen lassen. Darum darf dt nie größer als 1/30 Sekunde sein.

The real code: frame()

Der echte Code: frame()


    

clock.getDelta() measures the time since the last frame. Math.min(..., 1 / 30) is the hiccup guard.

clock.getDelta() misst die Zeit seit dem letzten Bild. Math.min(..., 1 / 30) ist der Schluckauf-Schutz.

state.inventoryOpen ? 0 : ... means: "if the inventory is open, use 0, otherwise ...". That is the pause.

state.inventoryOpen ? 0 : ... heißt: "Wenn das Inventar offen ist, nimm 0, sonst ...". Das ist die Pause.

timeScale comes from src/game/juice.js: it is 1 normally and 0.03 during a hit pause.

timeScale kommt aus src/game/juice.js: normalerweise 1, während einer Trefferpause 0,03.

Notice that the music gets elapsed, not dt. Why? So the music keeps playing while the game is paused!

Fällt dir auf, dass die Musik elapsed bekommt und nicht dt? Damit die Musik weiterspielt, während das Spiel pausiert!

requestAnimationFrame(frame) asks the browser to call frame again right before it shows the next picture.

requestAnimationFrame(frame) bittet den Browser, frame direkt vor dem nächsten Bild wieder aufzurufen.

Catching up, a little every frame

Jedes Bild ein bisschen aufholen

When the hero walks up a step, their body would jump up instantly. That looks jerky. So the game keeps two heights: where the hero is (y) and where we draw them (visY). Every frame the drawn one catches up a bit:

Wenn der Held eine Stufe hochgeht, würde sein Körper sofort nach oben springen. Das sieht ruckelig aus. Darum merkt sich das Spiel zwei Höhen: wo der Held ist (y) und wo wir ihn malen (visY). Jedes Bild holt die gemalte ein Stück auf:

player.visY += (player.y - player.visY) * Math.min(1, dt * 25);

"Move a part of the remaining way." Far away: big steps. Close: tiny steps. It slows down smoothly as it arrives.

"Geh einen Teil des restlichen Wegs." Weit weg: große Schritte. Nah dran: winzige Schritte. So wird es beim Ankommen sanft langsamer.

The camera turning (Q E), zooming and the colours changing as you go deeper all use the same trick.

Das Drehen der Kamera (Q E), das Zoomen und das Wechseln der Farben, wenn du tiefer gehst, benutzen alle denselben Trick.

A high catch-up speed feels snappy, a low one feels floaty. Game makers tune numbers like this until it feels right.

Ein hohes Aufholtempo fühlt sich zackig an, ein niedriges schwebend. Spielemacher drehen an solchen Zahlen, bis es sich richtig anfühlt.