Der Fehler passiert schnell: Du schreibst x += 4, das Quadrat läuft, alles sieht gut aus. Auf einem Rechner, der 60 Frames pro Sekunde schafft, sind das 240 Pixel pro Sekunde. Bei 30 Frames sind es nur noch 120, und das Spiel fühlt sich an wie in Zeitlupe.
Das orange Quadrat oben rechnet genau so, pro Frame. Ein Klick in die Demo wechselt die Bildrate auf 15, 30, 60 und 144, und das orange Quadrat wird mit ihr langsamer oder schneller. Das türkise darunter bleibt immer gleich schnell.
Pixel pro Sekunde mal Sekunden
Statt Pixel pro Frame rechnest du in Pixel pro Sekunde und multiplizierst mit der Zeit, die seit dem letzten Frame vergangen ist. Das ist die Delta Time:
const Uint64 now = SDL_GetPerformanceCounter(); const double delta = double(now - last) / SDL_GetPerformanceFrequency(); last = now; x += 240.0f * float(delta);
Bei 60 Frames ist delta etwa 0,0167 Sekunden, das Quadrat kommt auf 4 Pixel pro Frame. Bei 30 Frames sind es 0,033 Sekunden und 8 Pixel pro Frame. Pro Sekunde legt es in beiden Fällen 240 Pixel zurück.
Große Sprünge abfangen
Wechselst du den Tab oder hängt das Spiel kurz, ist delta plötzlich zwei Sekunden groß und das Quadrat springt quer durchs Bild, im schlimmsten Fall durch die Wand. In der Demo klemme ich die Zeit deshalb auf eine Viertelsekunde:
const double delta = std::min(sinceFrame, 0.25);
Für ein Quadrat reicht das. Sobald Physik und Kollisionen dazukommen, hängt das Ergebnis trotzdem von der Framerate ab, auch wenn sich alles ähnlich anfühlt. Dann willst du einen festen Zeitschritt, wie ihn die Update-Loop-Demo zeigt.
Beim Bauen der Demo hab ich mir selbst einen Bug eingebaut. Bei Zielrate 60 zeigte sie nur 40 Frames pro Sekunde. Ich hatte das Intervall exakt verglichen, und der Bildschirm liefert die Frames mal nach 16,6 und mal nach 16,7 Millisekunden. Jedes zweite Frame fiel knapp durch. Jetzt zählt ein Frame auch dann, wenn er zwei Millisekunden zu früh dran ist.
Den ganzen Code findest du im Repo unter delta-time. Alle Demos der Serie sammelt das Projekt Game Dev Snippets.