Kollision
Pyxen verwendet ein rasterbasiertes Kollisionssystem. Kollisionskörper leben auf einem räumlichen Raster und die Engine erkennt Überlappungen zwischen ihnen in jedem Frame. Das hält die Kollisionserkennung einfach, schnell und deterministisch.
Grid Maps und Grid Bodies
Eine GridMap definiert die räumliche Welt — ein Raster aus Kacheln mit einer gegebenen Zellgröße. Ein GridBody ist ein Kollisionsrechteck, das innerhalb dieses Rasters lebt.
Die Entität mit einer GridMap muss das Elternteil von Entitäten mit GridBody sein. Die Engine löst alle Kollisionen innerhalb einer einzelnen GridMap unabhängig auf, was bedeutet, dass du mehrere verschiedene GridMaps in derselben Welt betreiben kannst und sie nicht miteinander interagieren.
level = world.spawn(
map=GridMap(rows=20, columns=20, size=(16, 16), image="tileset")
)
player = world.spawn(
parent=level,
body=GridBody(pos=(32, 32), size=(16, 16), tag=1, mask=(2,))
)
Entitätsposition
Die Position der Entität (x, y) wird automatisch abgeleitet aus der GridMap-Kollisionsauflösung. Wenn die Engine die Körperbewegung auflöst, aktualisiert sie die Transformation der Entität entsprechend der aufgelösten Position des Körpers. Du setzt x/y nicht manuell bei Entitäten mit einem GridBody — das Kollisionssystem besitzt ihre Position.
Körper bewegen
Um eine Entität mit einem Body zu bewegen, setze die move-Eigenschaft des Bodies. Die Engine versucht die Bewegung und löst Kollisionen auf:
def update():
player.body.move = (0, 0)
if input.keyboard.right.down:
player.body.move = (2, 0)
Die Engine bewegt den Körper, prüft auf Kollisionen und passt die endgültige Position an.
Tags und Masken
Tags und Masken steuern, welche Körper miteinander kollidieren können.
- Tag — eine Zahl, die identifiziert, was dieser Körper ist (z.B. 1 = Spieler, 2 = Gegner, 3 = Wand)
- Mask — mit welchen Tags dieser Körper kollidieren soll
Wenn ein sich bewegender Körper auf einen anderen Körper oder eine Kachel trifft, deren Tag in seiner Maske ist, gleitet er daran entlang, anstatt durchzugehen. Das gibt dir solide Kollision mit flüssiger Bewegung an Wänden und Hindernissen entlang.
player = world.spawn(
parent=level,
body=GridBody(pos=(0, 0), size=(16, 16), tag=1, mask=(2, 3))
)
enemy = world.spawn(
parent=level,
body=GridBody(pos=(0, 0), size=(16, 16), tag=2, mask=(1,))
)
Der Spieler kollidiert mit Tags 2 und 3 (Gegner und Wände). Der Gegner kollidiert mit Tag 1 (dem Spieler). Körper mit Tag 0 oder ohne passende Maske gehen durcheinander hindurch.
Kollisions-Callbacks
Wenn ein Körper eine Kachel trifft, ruft die Engine on_hit_tile auf:
def on_hit_tile(entity, tile):
# Entität hat eine solide Kachel getroffen
pass
Wenn sich zwei Körper überlappen, ruft die Engine on_hit_body auf:
def on_hit_body(entity, other):
if entity == player:
entity.health.value -= 1
Diese laufen während des Kollisionsschritts, nach update() und vor dem Rendern.
Tilemap-Kollision
Eine GridMap definiert ein Raster aus Kacheln, und Kacheln können mit Kachel-Tags als solid markiert werden:
level.map.set(row=0, column=5, tile=(1, 0), tag=2)
Jeder Körper, dessen Maske diesen Tag enthält, gleitet an der Kachel entlang.
Wie es funktioniert
Das Kollisionssystem ist rasterbasiert, nicht pixelgenau. Körper sind achsenausgerichtete Rechtecke, die sich innerhalb des Rasters bewegen. Simulationen sind pro GridMap isoliert — jede GridMap-Entität führt ihre eigene unabhängige Kollisionsauflösung durch. Das macht Kollision:
- Deterministisch — gleiche Eingaben erzeugen immer gleiche Kollisionen
- Schnell — Rasterabfragen haben konstante Zeit
- Vorhersehbar — keine Gleitkomma-Grenzfälle
- Isoliert — mehrere GridMaps stören sich nicht gegenseitig