Entitäten & Komponenten
Pyxen verwendet ein Entity-Component-System (ECS). Wenn du Game Engines mit Klassenhierarchien kennst — wo ein Player Character extends GameObject erweitert — ist dies anders. In Pyxen gibt es keine Vererbung. Alles ist Komposition.
Entitäten
Eine Entität ist ein Spielobjekt. Es könnte ein Spieler, eine Wand, eine Kugel, ein Partikel sein — alles. Unter der Haube ist eine Entität nur eine ID. Sie hält keine eigenen Daten. Stattdessen hängst du Komponenten an sie an.
player = world.spawn(name="player", x=100, y=50)
Dies erzeugt eine Entität an Position (100, 50) mit einem Namen. Die Entität existiert in der Welt und wird gerendert, wenn sie ein Sprite hat.
Komponenten
Komponenten sind Datenstücke, die an eine Entität angehängt sind. Pyxen hat zwei Arten:
Eingebaute Komponenten
Diese werden von der Engine bereitgestellt:
| Komponente | Zweck |
|---|---|
| Transform | Position (x, y), Rotation, Skalierung |
| Sprite | Visuelles Erscheinungsbild — Bild, Kachel, Pivot, Farbe |
| Camera | Viewport mit Zoom |
| GridBody | Kollisionskörper auf dem Raster |
| GridMap | Tilemap mit Zeilen, Spalten und Kacheldaten |
| Sound | Soundeffekt-Wiedergabe |
| Music | Musik-Stream-Wiedergabe |
| Name | Zeichenketten-Bezeichner für Abfragen |
| Layer | Rendering-Ebene (0–255) |
| Parent / Children | Szenenhierarchie |
Du setzt eingebaute Komponenten über Entitätseigenschaften oder beim Erzeugen:
e = world.spawn(
x=50, y=80,
sprite=Sprite("hero"),
name="player"
)
# später
e.x = 100
e.sprite = Sprite("hero", tile=(16, 0, 16, 16))
Benutzerdefinierte Komponenten
Du kannst eigene Komponenten an jede Entität anhängen. Eine benutzerdefinierte Komponente ist ein Dictionary mit typisierten Feldern:
player.health = {"value": 100, "max": 100}
player.speed = {"value": 2.5}
Einmal angehängt, greifst du direkt auf Felder zu:
player.health.value -= 10
Du kannst auch Marker-Komponenten verwenden — Komponenten ohne Daten, die als Tags fungieren:
player.alive = True
enemy.boss = True
Das ist nützlich für Abfragen: Du kannst alle Entitäten mit einem bestimmten Marker finden.
Feldtypen
Komponentenfelder können sein:
| Typ | Beispiel | Hinweise |
|---|---|---|
int | 42 | 32-Bit-Integer |
float | 3.14 | 32-Bit-Float |
bool | True | Boolean |
str | "hello" | Max 31 Zeichen |
| Entity | player | Referenz auf eine andere Entität |
Diese Beschränkungen existieren, weil Komponenten in einem kompakten, cache-freundlichen Layout innerhalb der C++-Engine gespeichert werden. Das macht Abfragen schnell.
Entitäten abfragen
Die Welt ermöglicht es dir, Entitäten nach ihren Komponenten zu finden:
# alle Entitäten mit einer "health"-Komponente
for e in world.all("health"):
if e.health.value <= 0:
world.destroy(e)
# kombinieren: hat "enemy", hat nicht "dead"
for e in world.all("enemy", without=("dead",)):
e.x += e.speed.value
Du kannst auch nach eingebauten Komponenten wie "sprite", "body", "camera", "sound", "music" und "map" abfragen:
# alle Entitäten mit einem Sprite
for e in world.all("sprite"):
e.color = (1, 1, 1, 1)
# Entitäten mit sowohl einem Sprite als auch der benutzerdefinierten "enemy"-Komponente
for e in world.all("sprite", "enemy"):
e.color = (1, 0, 0, 1)
Abfragen sind die Hauptmethode, wie du Spiellogik in Pyxen schreibst. Statt dass sich jedes Objekt selbst aktualisiert, schreibst du Systeme, die über Entitäten mit bestimmten Komponenten iterieren.
Sieh die vollständige API: world.all(), Entity
Warum ECS?
Wenn du an objektorientiertem Spielcode gewöhnt bist, mag sich ECS zunächst ungewöhnlich anfühlen. Die Vorteile:
- Keine Klassenhierarchien — du musst nicht im Voraus entscheiden, ob ein PowerUp ein Collectible ist, das ein Entity ist. Hänge einfach die Komponenten an, die du brauchst.
- Einfaches Kombinieren von Verhalten — eine Entität kann gleichzeitig
health,enemy,flyingundboss-Komponenten haben, ohne Mehrfachvererbung. - Schnelle Abfragen — die Engine speichert Komponenten in zusammenhängendem Speicher, sodass das Iterieren über alle Entitäten mit einer bestimmten Komponente sehr effizient ist.
- Einfaches Debugging — jede Entität ist nur ein Bündel von Daten. Der Frame-Inspektor zeigt dir genau, was an jeder einzelnen angehängt ist.