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:

KomponenteZweck
TransformPosition (x, y), Rotation, Skalierung
SpriteVisuelles Erscheinungsbild — Bild, Kachel, Pivot, Farbe
CameraViewport mit Zoom
GridBodyKollisionskörper auf dem Raster
GridMapTilemap mit Zeilen, Spalten und Kacheldaten
SoundSoundeffekt-Wiedergabe
MusicMusik-Stream-Wiedergabe
NameZeichenketten-Bezeichner für Abfragen
LayerRendering-Ebene (0–255)
Parent / ChildrenSzenenhierarchie

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:

TypBeispielHinweise
int4232-Bit-Integer
float3.1432-Bit-Float
boolTrueBoolean
str"hello"Max 31 Zeichen
EntityplayerReferenz 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: