Framerate-unabhängige Spiellogik

Aus Spieleprogrammierer-Wiki
Wechseln zu: Navigation, Suche

In diesem Artikel wird die Frage betrachtet, wie man sein Spiel so programmiert, dass es unabhängig von der Framerate bzw. unabhängig von der Geschwindigkeit des Computers immer gleich schnell abläuft.

Einleitung

Wer sich noch an die Anfangszeit der Computerspiele erinnern kann, der wird sich vielleicht auch an eine Eigenart einiger damaliger Spiele erinnern. Viele von ihnen waren für spezielle Computer programmiert und an deren Rechengeschwindigkeit angepasst. Versuchte man sie auf einem neueren, schnelleren Computer zu spielen, so liefen sie dort viel schneller ab als auf dem Rechner, für den sie entwickelt wurden. Was diesen Spielen fehlte, war also eine Framerate-unabhängige Spiellogik. Diese Spiele berechneten ihre Spiellogik einfach so oft wie es möglich war, ohne auf die vergangene Zeit zu achten und sicherzustellen, dass sie nicht zu schnell oder zu langsam laufen. Heutige Computerspiele können sich so etwas nicht mehr leisten. Selbst solche für Konsolen nicht, obwohl deren Rechenleistung genau bekannt und festgelegt ist, denn auch dort kommt es vor, dass das Spiel stellenweise mehr oder weniger Zeit benötigt, um die Grafik zu zeichnen und die Spiellogik zu berechnen.

Ein typischer Main-Loop

Der Teil des Spiels, um den es in diesem Artikel geht, ist der Main-Loop. Das ist die Schleife, die während des ganzen Spiels ständig durchlaufen wird und in der die Spiellogik, Grafik, Audio usw. koordiniert werden. Ein solcher Main-Loop könnte in Pseudocode wie folgt aussehen:

Solange das Spiel nicht beendet werden soll:
    SpielzustandZeichnen()
    SpielzustandAktualisieren()
    FertigesBildAnzeigen()

In SpielzustandZeichnen werden die Zeichenbefehle an die Grafikhardware übermittelt. Während diese dann mit dem Rendering beschäftigt ist, kann die Spiellogik in SpielzustandAktualisieren berechnet werden. Anschließend wird das fertige Bild angezeigt (zuvor muss normalerweise auf die vertikale Synchronisation gewartet werden, damit das Bild vollständig sichtbar wird).

In der oben gezeigten Version fehlt jedoch noch die Komponente Zeit. Die Geschwindigkeit des Spiels ist direkt an die Anzahl der Schleifendurchläufe pro Sekunde gekoppelt, und das ist unerwünscht. Darum messen wir für jeden Schleifendurchlauf die benötigte Zeit Δt und teilen der Funktion SpielzustandAktualisieren im nächsten Durchlauf mit, dass sie das Spiel um genau dieses Zeitintervall weiter berechnen/simulieren soll.

Δt = 0
Solange das Spiel nicht beendet werden soll:
    t0 = Zeit()
    SpielzustandZeichnen()
    SpielzustandAktualisieren(Δt)
    FertigesBildAnzeigen()
    Δt = (Zeit() - t0)

Nun liegt es in der Verantwortung der Funktion SpielzustandAktualisieren, dass sie das Spiel um Δt Sekunden weiter berechnet.

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Werkzeuge