Game Loop

Pyxen führt dein Spiel mit festen 30 Frames pro Sekunde aus. Du schreibst keine Hauptschleife — du definierst zwei Funktionen und Pyxen ruft sie für dich auf.

start() und update()

def start():
    # wird einmal aufgerufen, am Anfang
    pass

def update():
    # wird jeden Frame aufgerufen, 30 Mal pro Sekunde
    pass

start() ist, wo du deine Welt einrichtest: Entitäten erzeugen, platzieren, die Szene konfigurieren.

update() ist, wo deine Spiellogik läuft: Eingaben lesen, Entitäten bewegen, Bedingungen prüfen, Zustand aktualisieren. Nach jedem Aufruf von update() rendert die Engine den Frame.

Feste Bildrate

Jeder Frame dauert genau gleich lang: 1/30 Sekunde (~33ms). Das bedeutet:

Du kannst immer noch time.dt (Delta-Zeit) verwenden, wenn du zeitbasierte Bewegung bevorzugst, aber es wird immer 1/30 sein.

Frame-Reihenfolge

Jeden Frame führt Pyxen diese Schritte in dieser Reihenfolge aus:

  1. Eingabe — lies Tastatur-, Maus-, Touch- und Gamepad-Zustand
  2. update() — dein Code wird ausgeführt
  3. Kollision — die Engine löst Grid-Bodies auf und ruft Kollisions-Callbacks auf
  4. Rendern — die Engine zeichnet alle sichtbaren Entitäten

Das bedeutet, wenn du Eingaben in update() liest, sind die Werte aktuell. Wenn du eine Entität bewegst, passiert die Kollisionsauflösung direkt danach.

Kollisions-Callbacks

Wenn du on_collision oder on_tile_collision auf oberster Ebene definierst, ruft die Engine sie während des Kollisionsschritts auf:

def on_collision(entity, other):
    # zwei Grid-Bodies haben sich überlappt
    pass

def on_tile_collision(entity, tile):
    # ein Grid-Body hat eine Tilemap-Kachel getroffen
    pass

Diese laufen nach update(), aber vor dem Rendern.

Timing

Das pyxen.time-Modul gibt dir:

EigenschaftWertVerwendung
time.frame0, 1, 2, ...Frame-Zähler seit Start
time.dt0.0333...Delta-Zeit (immer 1/30)
time.t0.0, 0.033, 0.066, ...Vergangene Zeit in Sekunden
time.fps30Frames pro Sekunde

Für zeitgesteuerte Ereignisse kannst du beide Ansätze verwenden:

# Frame-basiert: alle 60 Frames feuern (2 Sekunden)
if time.frame % 60 == 0:
    fire()

# Zeit-basiert: dasselbe
if int(time.t * 30) % 60 == 0:
    fire()

Frame-Zählung ist normalerweise einfacher und vorhersehbarer.