Sprites & Rendering

Pyxen rendert dein Spiel mit einem Metal-gestützten 2D-Renderer. Alles, was auf dem Bildschirm sichtbar ist, ist eine Entität mit einer Sprite-Komponente.

Sprites

Ein Sprite sagt der Engine, was sie für eine Entität zeichnen soll. Du erstellst eins, indem du ein Bild aus deinem Projekt referenzierst:

player = world.spawn(sprite=Sprite("hero"))

Die Zeichenkette "hero" bezieht sich auf ein Bild namens hero in den Assets deines Projekts.

Kachel-Sheets

Die meisten Spiele verwenden Kachel-Sheets — ein einzelnes Bild mit vielen Frames oder Kacheln, die in einem Raster angeordnet sind. Du wählst einen Bereich des Bildes mit dem tile-Parameter:

Sprite("characters", tile=(0, 0, 16, 16))    # erste Kachel
Sprite("characters", tile=(16, 0, 16, 16))   # zweite Kachel
Sprite("characters", tile=(0, 16, 16, 16))   # Kachel in zweiter Reihe

Die vier Werte sind (x, y, Breite, Höhe) in Pixeln, gemessen von der oberen linken Ecke des Bildes.

Sprite-Animationen

Wenn du benannte Animationen im Sprite-Editor erstellst, kannst du sie direkt abspielen:

player = world.spawn(
    sprite=Sprite("hero", animation="walk"),
    x=100, y=50
)

Die Engine liest die Frame-Sequenz und FPS aus den Metadaten des Sprites und wechselt die Frames automatisch. Um Animationen zu wechseln, weise ein neues Sprite zu:

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

Für einmalige Animationen (wie ein Angriff oder Tod) setze loop=False und prüfe, wann sie fertig ist:

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

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

Die e.animation-Komponente gibt dir schreibgeschützten Zugriff auf den aktuellen Zustand: .name, .frame, .playing, .finished. Siehe die Entity-Referenz für Details.

Du kannst auch manuell animieren, indem du die Kachel in jedem Frame änderst:

def update():
    frame = time.frame % 4
    player.sprite = Sprite("hero", tile=(frame * 16, 0, 16, 16))

Pivot-Punkt

Standardmäßig wird ein Sprite von seiner oberen linken Ecke gezeichnet. Du kannst den Pivot-Punkt ändern, um zu steuern, wo das Sprite verankert ist:

Sprite("hero", tile=(0, 0, 16, 16), pivot=(8, 8))

Dies zentriert das Sprite auf der Position der Entität. Der Pivot ist in Pixelkoordinaten relativ zur Kachel. Den Pivot auf die Mitte der Kachel zu setzen ist die häufigste Wahl — es lässt Rotation und Skalierung intuitiv funktionieren.

Farbtönung

Du kannst das Sprite jeder Entität tönen, indem du ihre Farbe setzt:

player.color = (1.0, 0.5, 0.5, 1.0)  # rötliche Tönung

Farbe ist ein RGBA-Tupel mit Werten von 0.0 bis 1.0. Weiß (1, 1, 1, 1) bedeutet keine Tönung. Du kannst den Alpha-Kanal für Transparenz verwenden:

ghost.color = (1, 1, 1, 0.5)  # 50% transparent

Du kannst Farbe und Alpha mit Tweens flüssig animieren:

ghost.tween("alpha", to=0, duration=0.5, ease="out_quad")  # ausblenden

Für kontinuierliche Effekte wie Pulsieren oder Flackern verwende Animationen:

ghost.animate("alpha", by=0.3, center=0.7, speed=4.0)  # flackern

Kamera

Die Kamera steuert, welcher Teil der Welt sichtbar ist. Erstelle eine, indem du eine Entität mit einer Camera-Komponente erzeugst:

cam = world.spawn(camera=Camera(), x=160, y=90)

Bewege die Kamera, um dem Spieler zu folgen:

def update():
    cam.x = player.x
    cam.y = player.y

Die Kamera unterstützt Zoom:

cam.camera.zoom = 2.0  # 2-fach hineinzoomen

Du kannst den Zoom mit einem Tween flüssig animieren:

cam.tween("zoom", to=2.0, duration=0.5, ease="out_quad")

Auflösung

Pyxen-Spiele laufen mit einer Standardauflösung von 320x180 Pixeln. Das ist eine bewusste Wahl — niedrige Auflösung lässt Pixel Art scharf aussehen und hält das Rendering schnell. Die Engine skaliert die Ausgabe, um den Bildschirm zu füllen.

Text

Die Text-Komponente rendert Bitmap-Text. Erstelle ein Text-Entity so:

label = world.spawn(text=Text("Hello, world!"))

Standardmäßig verwendet Text die eingebaute Pixel-Schriftart. Um eine eigene Schriftart zu verwenden, die mit dem Schriftart-Editor erstellt wurde:

title = world.spawn(text=Text("Game Over", font="myfont"))

Aktualisiere den Text zur Laufzeit, indem du die text-Eigenschaft änderst:

def update():
    score_label.text = Text(f"Score: {score}")

Siehe die Text-Referenz für die vollständige API.

Zeichenreihenfolge

Entitäten werden in dieser Reihenfolge gezeichnet:

  1. Ebene — niedrigere Ebenen werden zuerst gezeichnet (Ebene 0 hinter Ebene 1)
  2. Tiefe — innerhalb einer Ebene, bestimmt durch die Position im Szenengraph
  3. Entitäten ohne Sprites werden nicht gezeichnet, existieren aber trotzdem in der Welt

Siehe Szenengraph für mehr über Ebenen und Tiefe.

Für die vollständige Sprite-API, siehe Sprite und Camera.