pyxen.Entity

Ein Entity ist ein leichtgewichtiger Handle — ein Container für Components.

Eine Einführung in das Entity-Component-System findest du unter Entities und Components.


Eingebaute Components

ComponentZugriff
Transforme.x, e.y, e.rotation, e.scale
Spritee.sprite, e.color
Animatione.animation
Sounde.sound
Musice.music
GridBodye.body
GridMape.map
Nodee.parent, e.children
Layere.layer
Namee.name
Camerae.camera

Transform

e.x = 100
e.y = 50
e.rotation = 45
e.scale = (2, 2)

Das Lesen von scale gibt einen Vector2 zurück:

s = e.scale
print(s.x, s.y)

Sprite

e.sprite = sprite
e.color = (1.0, 0.5, 0.5, 1.0)

Das Lesen von color gibt ein Color-Objekt zurück:

c = e.color
print(c.r, c.g, c.b, c.a)

Sprite-Animation

Wenn ein Sprite mit dem animation-Parameter erstellt wird, spielt die Engine die Animation automatisch ab. Du kannst den Animationszustand über e.animation auslesen:

player.sprite = Sprite("hero", animation="walk")

Eigenschaften

EigenschaftTypBeschreibung
namestrName des aktuellen Animationsclips
frameintAktueller Frame-Index innerhalb des Clips
playingboolTrue wenn die Animation aktiv abgespielt wird
finishedboolTrue wenn eine einmalige Animation beendet ist
anim = player.animation
if anim:
    print(anim.name)      # "walk"
    print(anim.frame)     # 2
    print(anim.playing)   # True
    print(anim.finished)  # False

Wenn keine Animation aktiv ist, gibt e.animation None zurück:

player.sprite = Sprite("hero", tile=(0, 0, 16, 16))
print(player.animation)  # None

Abbrechen

Setze e.animation auf None, um die Wiedergabe zu stoppen:

player.animation = None

Das Zuweisen eines neuen Sprites bricht automatisch jede bestehende Animation ab.

Einmalige Animationen

Verwende loop=False für Animationen, die nur einmal abgespielt werden:

player.sprite = Sprite("hero", animation="attack", loop=False)

def update():
    if player.animation and player.animation.finished:
        player.sprite = Sprite("hero", animation="idle")

Tweens

Tweens animieren die Eigenschaften einer Entität über die Zeit. Die Engine übernimmt die Interpolation automatisch — kein Code pro Frame nötig.

entity.tween()

# Benannte Eigenschaft
entity.tween("x", to=200, duration=1.0)
entity.tween("alpha", to=0, duration=0.5, ease="out_quad")

# Kurzschreibweise — mehrere Eigenschaften gleichzeitig animieren
entity.tween(x=200, y=100, duration=1.0, ease="out_quad")
ParameterTypStandardBeschreibung
propertystrEigenschaftsname (positional oder Kurzschreibweise)
tofloatZielwert
byfloatRelativer Offset (Alternative zu to)
startfloataktuellStartwert (standardmäßig der aktuelle Wert)
durationfloat1.0Dauer in Sekunden
easestr"linear"Name der Easing-Funktion

Verwende to für einen absoluten Zielwert oder by für einen relativen Offset:

entity.tween("x", to=200, duration=1.0)    # bewege zu x=200
entity.tween("x", by=50, duration=0.5)     # bewege 50 Pixel nach rechts

Verwende start, um den Startwert zu überschreiben:

entity.tween("x", to=200, start=0, duration=1.0)  # immer von 0 starten

Animierbare Eigenschaften

KomponenteEigenschaften
Transformx, y, rotation, sx, sy
Spriter, g, b, alpha
Camerazoom

Easing-Funktionen

NameKurve
linearKonstante Geschwindigkeit (Standard)
in_quadLangsamer Start, beschleunigend
out_quadSchneller Start, verlangsamend
in_out_quadLangsamer Start und Ende
in_cubicLangsamerer Start als Quad
out_cubicSchnellerer Start als Quad
in_out_cubicSanfter langsamer Start und Ende
in_expoSehr langsamer Start, explosive Beschleunigung
in_out_expoExplosive Mitte
out_expoSehr schneller Start, sanfter Stopp
in_backZieht zurück bevor es vorwärts geht
out_backÜberschießt das Ziel, pendelt sich ein
in_out_backZurückziehen und Überschießen
in_elasticElastisches Aufziehen
out_elasticElastisches Überschießen und Schwingen
in_out_elasticElastisch an beiden Enden

entity.tweens.cancel()

Bricht Tweens einer Entität ab. Übergeben Sie einen Eigenschaftsnamen, um einen einzelnen Tween abzubrechen, oder rufen Sie ohne Argument auf, um alle Tweens abzubrechen. Der Wert bleibt an seiner aktuellen Position stehen.

entity.tweens.cancel("x")   # einen Tween abbrechen
entity.tweens.cancel()       # alle abbrechen

Konfliktlösung

Ein neuer Tween auf derselben Entität und Eigenschaft ersetzt den vorherigen. Tweens auf verschiedenen Eigenschaften laufen unabhängig voneinander.

entity.tween("x", to=100, duration=1.0)
entity.tween("x", to=200, duration=0.5)  # ersetzt den ersten Tween
entity.tween("y", to=50, duration=1.0)   # läuft neben dem x-Tween

Tweens auf zerstörten Entitäten werden automatisch aufgeräumt.

Ein animate() auf einer Eigenschaft bricht jeden aktiven tween() auf dieser Eigenschaft ab und umgekehrt.


Animationen

Kontinuierliche Animationen, die unbegrenzt laufen — Sinuswellen-Oszillation (Pulsieren, Atmen, Wippen) und konstante Drehung.

entity.animate() — Oszillieren

Lässt eine Eigenschaft mit einer Sinuswelle um einen Mittelwert oszillieren.

entity.animate("sx", "sy", by=0.15, speed=6.0)     # coin pulse
entity.animate("alpha", by=0.3, center=0.7, speed=4.0)  # flicker 0.4–1.0

Der Wert folgt: center + sin(elapsed * speed) * by

entity.animate() — Drehen

Akkumuliert einen Wert mit konstanter Rate. Lassen Sie by= weg, um den Drehmodus zu verwenden.

entity.animate("rotation", speed=180)   # 180°/sec clockwise

Parameter

ParameterTypStandardBeschreibung
*propsstrEin oder mehrere Eigenschaftsnamen (positional)
byfloatAmplitude (Oszillationsmodus). Weglassen für Drehung.
centerfloataktuellMittelwert für die Oszillation
speedfloat1.0Winkelfrequenz (Oszillation) oder Einheiten/Sek (Drehung)

Dieselben 10 Eigenschaften wie bei Tweens: x, y, rotation, sx, sy, r, g, b, alpha, zoom.

entity.animations.cancel()

Bricht Animationen einer Entität ab. Übergeben Sie einen Eigenschaftsnamen, um eine einzelne Animation abzubrechen, oder rufen Sie ohne Argument auf, um alle Animationen abzubrechen.

entity.animations.cancel("rotation")   # eine Animation abbrechen
entity.animations.cancel()             # alle abbrechen

Parent / Children

child.parent = parent

Zugriff auf Kinder:

for c in parent.children:
    print(c.name)

Anzahl der Kinder abfragen:

parent.children.count

Eigene Components

Components werden durch Zuweisung erstellt:

  • Ein Dictionary — strukturierte Komponente
  • Ein Boolean — Marker-Komponente
e.cell = {
    'row': 0,
    'col': 0
}

Die erste Zuweisung erstellt das Schema. Feldtypen werden abgeleitet und das Schema ist danach fixiert — du kannst später keine neuen Felder hinzufügen.


Components in Systemen verwenden

for cell in world.all("cell"):
    ...

Siehe: pyxen.world.all()


Marker-Components

e.alive = True

Marker speichern keine Daten — sie zeigen nur Vorhandensein an. Abfragen funktionieren wie bei normalen Components:

for e in world.all("alive"):
    ...

Auf Component-Felder zugreifen

e.cell.row
e.cell.col
e.cell.row = 5

Unterstützte Feldtypen

Python-TypGespeichert als
int32-Bit-Ganzzahl
float32-Bit-Gleitkommazahl
boolBoolean
strFester String (max. 31 Zeichen)
EntityEntity-Referenz

Ungültige Typen lösen aus:

TypeError: invalid value type in dict

Schema-Regeln

  • Maximale Komponentengröße: 256 Bytes
  • Strings maximal: 31 Zeichen
  • Dict-Schlüssel müssen Strings sein
  • Keine neuen Felder nach Schema-Erstellung möglich
e.cell = {'row': 0}
e.cell = {'row': 0, 'new_field': 5}
ValueError: cannot create new fields after schema is complete

Es ist erlaubt, Felder bei nachfolgenden Zuweisungen wegzulassen — sie werden auf 0, 0.0, False, "" usw. gesetzt.


Auf eine Komponente prüfen

e.has("cell")

Gibt True zurück, wenn das Entity die Komponente hat, sonst False.

Das funktioniert sowohl für eigene als auch eingebaute Komponentennamen:

e.has("sprite")   # True wenn das Entity ein Sprite hat
e.has("body")     # True wenn das Entity einen Grid-Body hat

Nachkommen abfragen

entity.all(*components, without=(), include_self=False)

Gibt einen Iterator über alle Nachkommen des Entity zurück (Tiefensuche durch die Szenengraph-Hierarchie), die dem gegebenen Komponentenfilter entsprechen.

Funktioniert genau wie world.all(), aber beschränkt auf einen Teilbaum statt die gesamte Welt.

# Alle Nachkommen mit "enemy"-Komponente
for e in parent.all("enemy"):
    ...

# Mit Ausschluss
for e in parent.all("enemy", without=("boss",)):
    ...

# Das Eltern-Entity selbst einschließen
for e in parent.all("tag", include_self=True):
    ...
ParameterTypStandardBeschreibung
*componentsstrErforderliche Komponentennamen
withouttuple()Auszuschließende Komponentennamen
include_selfboolFalseOb das Entity selbst eingeschlossen wird

Sowohl eingebaute als auch eigene Komponentennamen werden unterstützt.


Components entfernen

Entferne eine Komponente von einem Entity mit del oder durch Zuweisung von None:

# Beide sind gleichwertig:
del entity.health
entity.health = None

Nach dem Entfernen gibt entity.has("health") False zurück und das Entity wird nicht mehr in Abfragen für diese Komponente gefunden.

e = world.spawn()
e.health = {'hp': 100}

del e.health

e.has("health")         # False
# world.all("health") enthält e nicht mehr

Du kannst eine Komponente nach dem Entfernen erneut hinzufügen:

del e.health
e.health = {'hp': 50}   # funktioniert problemlos

Eingebaute Components

Alle eingebauten Components können entfernt werden:

del e.sprite    # löscht Sprite-Daten
del e.body      # löscht Physics-Body
del e.camera    # entfernt Kamera
del e.text      # entfernt Text
del e.sound     # entfernt Sound
del e.music     # entfernt Musik
del e.map       # entfernt Grid-Map

Sprite und Body werden auf Null initialisiert (das Entity behält den Speicher, aber die Daten sind leer). Camera, Text, Sound, Music und Map werden vollständig gelöscht.

Marker

e.enemy = True
del e.enemy      # oder: e.enemy = None
e.has("enemy")   # False

Entity-Lebenszyklus

  • Erstellt mit world.spawn()
  • Geändert durch Komponentenzuweisung
  • Components entfernt mit del oder = None
  • Zerstört mit world.destroy()

Siehe: pyxen.world.spawn() | pyxen.world.destroy()