Home › Pyglet 2.1

🦅 Pyglet 2.1 – Vollständiger Guide

INTERMEDIATE ⏱ ~60 Min Pyglet 2.1.x

Was ist Pyglet?

Pyglet (aktuell v2.1.x) ist eine leistungsstarke, plattformübergreifende Python-Bibliothek für Spiele und multimediale Anwendungen. Sie ist die Basis unter Python Arcade – Arcade baut intern auf Pyglet auf! Wer Pyglet versteht, versteht auch Arcades Innenleben.

🔗 Versionshinweis: Pyglet 2.0+ brachte massive Änderungen: Programmable Pipeline (kein fixer OpenGL-State mehr), überarbeitetes Event-System, neue Shader-API. Pyglet 2.1 ist die aktuelle stabile Version (2025).

🎮 Für Spiele

Window-Management, Input-Handling, Sprites, Sound – alles für 2D-Spiele inklusive.

🖥️ OpenGL-Basis

Direkter OpenGL-Zugriff. Für Custom-Shader und Effekte unschlagbar flexibel.

📦 Keine Abhängigkeiten

Nur Python Standard Library + OpenGL. Kein SDL, kein externe C-Lib nötig.

🔊 Audio

Media-Player, Streaming, 3D-Sound via OpenAL. Vollständige Audio-Pipeline.

TERMINAL – Pyglet installieren
# Pyglet 2.1 installieren
pip install pyglet

# Version prüfen
python -c "import pyglet; print(pyglet.version)"

# Optionale Erweiterungen
pip install pyglet[image]   # Erweiterte Bildformate
pip install pyglet[audio]   # Erweiterte Audioformate via FFmpeg
Pyglet vs Arcade – Abstraktions-Ebenen

Fenster & Events

Pyglet-Fenster werden als pyglet.window.Window-Objekte erstellt. Events werden via Dekorator oder Subklasse registriert.

PYTHON – Minimales Pyglet-Fenster
import pyglet

# Fenster erstellen
window = pyglet.window.Window(
    width=800,
    height=600,
    caption="Mein Pyglet-Fenster",
    resizable=True,
    fullscreen=False
)

# Hintergrundfarbe (RGBA 0.0–1.0)
pyglet.gl.glClearColor(0.1, 0.1, 0.2, 1.0)

@window.event
def on_draw():
    window.clear()
    # Hier zeichnen

@window.event
def on_key_press(symbol, modifiers):
    if symbol == pyglet.window.key.ESCAPE:
        window.close()

pyglet.app.run()
PYTHON – Window Subklasse
import pyglet

class GameWindow(pyglet.window.Window):
    def __init__(self):
        super().__init__(800, 600, caption="Game")
        self.batch = pyglet.graphics.Batch()
        self.fps_display = pyglet.window.FPSDisplay(window=self)
        self.player_x = 400

    def on_draw(self):
        self.clear()
        self.batch.draw()
        self.fps_display.draw()

    def on_update(self, dt):
        self.player_x += 100 * dt  # frame-rate-unabhängig

    def on_key_press(self, symbol, modifiers):
        if symbol == pyglet.window.key.F11:
            self.set_fullscreen(not self.fullscreen)

window = GameWindow()
pyglet.clock.schedule_interval(window.on_update, 1/60)
pyglet.app.run()
PYTHON – Alle wichtigen Events
@window.event
def on_draw():
    """Jeden Frame: zeichnen."""
    window.clear()

@window.event
def on_key_press(symbol, modifiers):
    """Taste gedrückt."""
    print(pyglet.window.key.symbol_string(symbol))

@window.event
def on_key_release(symbol, modifiers):
    """Taste losgelassen."""

@window.event
def on_mouse_press(x, y, button, modifiers):
    """Mausklick bei (x,y)."""
    print(f"Klick: {x}, {y}, Button: {button}")

@window.event
def on_mouse_motion(x, y, dx, dy):
    """Mausbewegung. dx/dy = Delta."""

@window.event
def on_resize(width, height):
    """Fenstergröße geändert."""
    print(f"Neue Größe: {width}x{height}")
Event-Simulator – Klicke & bewege die Maus im Feld
Bewege die Maus oder klicke hier...

Grafik & Batch-Rendering

Pyglets Batch-System gruppiert Zeichenoperationen für maximale GPU-Effizienz. Groups steuern die Zeichenreihenfolge (Z-Order).

PYTHON – Batch & Groups
import pyglet
from pyglet.graphics import Batch, Group

window = pyglet.window.Window(800, 600)
batch = Batch()

# Groups für Z-Order (niedrigere Order = weiter hinten)
bg_group = Group(order=0)    # Hintergrund
fg_group = Group(order=1)    # Vordergrund
ui_group = Group(order=2)    # UI ganz oben

# Sprite laden und zur Batch hinzufügen
img = pyglet.resource.image("player.png")
img.anchor_x = img.width // 2
img.anchor_y = img.height // 2

player = pyglet.sprite.Sprite(
    img,
    x=400, y=300,
    batch=batch,
    group=fg_group
)

# Mehrere Sprites effizient
coins = []
for i in range(20):
    coin = pyglet.sprite.Sprite(
        pyglet.resource.image("coin.png"),
        x=i*40, y=100,
        batch=batch,  # Gleicher Batch!
        group=fg_group
    )
    coins.append(coin)

@window.event
def on_draw():
    window.clear()
    batch.draw()  # ALLE Sprites in einem Draw Call

# Sprite-Attribute
player.x = 200
player.y = 400
player.rotation = 45    # Grad (im Uhrzeigersinn bei Pyglet!)
player.scale = 2.0
player.opacity = 128    # 0-255
player.visible = False
⚠️ Pyglet vs Arcade Koordinaten: Pyglet hat (0,0) unten links (wie Arcade). Aber rotation in Pyglet dreht im Uhrzeigersinn, in Arcade gegen den Uhrzeigersinn!

Pyglet Shapes (2.0+)

Seit Pyglet 2.0 gibt es pyglet.shapes für einfaches Zeichnen von Grundformen – ohne OpenGL-Direktzugriff.

PYTHON – pyglet.shapes
import pyglet
import pyglet.shapes

window = pyglet.window.Window(800, 600)
batch = pyglet.graphics.Batch()

# Kreis
circle = pyglet.shapes.Circle(
    x=400, y=300,
    radius=80,
    color=(255, 100, 0, 255),  # RGBA!
    batch=batch
)

# Rechteck
rect = pyglet.shapes.Rectangle(
    x=50, y=50,
    width=200, height=100,
    color=(0, 200, 255),
    batch=batch
)

# Linie
line = pyglet.shapes.Line(
    x=0, y=0,
    x2=800, y2=600,
    width=3,
    color=(255, 255, 0),
    batch=batch
)

# Bogen
arc = pyglet.shapes.Arc(
    x=600, y=400,
    radius=60,
    angle=3.14,     # Radiant! 3.14 = 180°
    color=(255, 0, 200),
    batch=batch
)

# Stern
star = pyglet.shapes.Star(
    x=200, y=200,
    outer_radius=60,
    inner_radius=25,
    num_spikes=5,
    color=(255, 220, 0),
    batch=batch
)

# Ellipse
ellipse = pyglet.shapes.Ellipse(
    x=600, y=150,
    a=100, b=50,  # Halb-Achsen
    color=(0, 255, 100),
    batch=batch
)

# Polygon
poly = pyglet.shapes.Polygon(
    (100,500), (200,550), (250,480), (150,430),
    color=(200, 50, 255),
    batch=batch
)

@window.event
def on_draw():
    window.clear()
    batch.draw()
Pyglet Shapes Simulator – Zeichne interaktiv
Größe: 40
Klicke ins Feld um eine Form zu zeichnen...

Text & Fonts

PYTHON – pyglet.text.Label / HTMLLabel
import pyglet

# Einfaches Label
label = pyglet.text.Label(
    text="Score: 1337",
    font_name="Arial",
    font_size=24,
    x=10, y=580,
    anchor_x="left",
    anchor_y="top",
    color=(255, 255, 255, 255),  # RGBA!
    batch=batch
)

# Mehrzeiliges HTML-Label
html_label = pyglet.text.HTMLLabel(
    text="<b>Fett</b> und <i>kursiv</i>",
    x=200, y=300,
    width=300,
    multiline=True
)

# Schrift aus Datei laden
pyglet.font.add_file("fonts/Orbitron.ttf")
custom_label = pyglet.text.Label(
    text="Custom Font!",
    font_name="Orbitron",
    font_size=30,
    x=400, y=300,
    anchor_x="center",
    anchor_y="center"
)

# Text animieren
def update(dt):
    label.text = f"Zeit: {pyglet.clock.get_default().time:.1f}s"

pyglet.clock.schedule_interval(update, 0.1)

Sound & Media

Pyglets Media-System unterstützt Audio und Video. Der MediaPlayer ist die Kern-Klasse für Wiedergabe.

PYTHON – pyglet.media
import pyglet

# Sound statisch laden (kurze SFX)
sfx = pyglet.media.load("sounds/coin.wav", streaming=False)
sfx.play()

# Musik als Stream (große Dateien)
music = pyglet.media.load("sounds/background.mp3", streaming=True)
player = pyglet.media.Player()
player.queue(music)
player.loop = True
player.volume = 0.3
player.play()

# Lautstärke und Pan steuern
player.volume = 0.5    # 0.0–1.0
player.pitch = 1.0     # Tonhöhe (0.5=halbe, 2.0=doppelte)

# 3D-Sound (OpenAL Backend)
player.position = (100, 0, 0)   # 3D-Raumposition
pyglet.media.get_audio_driver().get_listener().position = (0, 0, 0)

# Auf Event reagieren wenn Sound endet
@player.on("on_eos")
def on_end_of_stream():
    print("Sound fertig!")

# Wiedergabe pausieren/fortsetzen
player.pause()
player.play()

# Stoppen
player.delete()

Clock & Scheduling

Pyglets Clock ist der Timer-Dienst – für regelmäßige Updates, verzögerte Aktionen und FPS-Management.

PYTHON – pyglet.clock
import pyglet

# Funktion alle N Sekunden aufrufen
def spawn_enemy(dt):
    print(f"Neuer Gegner! dt={dt:.3f}s")

pyglet.clock.schedule_interval(spawn_enemy, interval=2.0)

# Funktion einmalig nach Verzögerung
def game_start(dt):
    print("Spiel startet jetzt!")

pyglet.clock.schedule_once(game_start, delay=3.0)

# So schnell wie möglich (jeden Frame)
def update(dt):
    player.x += 200 * dt  # Frame-rate-unabhängig

pyglet.clock.schedule(update)

# Timer stoppen
pyglet.clock.unschedule(spawn_enemy)

# FPS begrenzen
pyglet.clock.set_fps_limit(60)

# Aktuelle FPS
fps = pyglet.clock.get_fps()

# Elapsed time seit Start
elapsed = pyglet.clock.get_default().time
Scheduling Simulator – Sieh wie Intervalle funktionieren
Intervall (s): 0.5s

FPS Display & Timing

PYTHON – FPS & Profiling
import pyglet

window = pyglet.window.Window(800, 600)

# Eingebauter FPS-Counter
fps_display = pyglet.window.FPSDisplay(window=window)

# Eigener FPS-Counter
fps_label = pyglet.text.Label("FPS: ?", x=10, y=10)

def update_fps(dt):
    fps = pyglet.clock.get_fps()
    fps_label.text = f"FPS: {fps:.1f}"

pyglet.clock.schedule_interval(update_fps, 0.5)

@window.event
def on_draw():
    window.clear()
    fps_display.draw()  # Eingebauter Counter
    fps_label.draw()    # Eigenes Label

# Frame-Zeit messen
import time
def timed_update(dt):
    start = time.perf_counter()
    # ... teure Operation ...
    elapsed = time.perf_counter() - start
    if elapsed > 0.016:  # > 16ms = Frame-Drop
        print(f"Frame zu langsam: {elapsed*1000:.1f}ms")

OpenGL direkt nutzen

Pyglet erlaubt direkten Zugriff auf OpenGL – für Custom Shader, Framebuffer, Vertex Buffer Objects und mehr.

PYTHON – Shader in Pyglet 2.1
import pyglet
from pyglet.gl import *

window = pyglet.window.Window(800, 600)

# Vertex & Fragment Shader schreiben
vert_shader = """
#version 330 core
in vec2 position;
void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}
"""

frag_shader = """
#version 330 core
uniform float time;
out vec4 color;
void main() {
    float r = 0.5 + 0.5 * sin(time);
    color = vec4(r, 0.5, 1.0 - r, 1.0);
}
"""

# Shader-Programm erstellen
program = pyglet.gl.current_context.create_program(
    (vert_shader, "vertex"),
    (frag_shader, "fragment")
)

# Uniform setzen
program["time"] = 0.0

def update(dt):
    program["time"] += dt

pyglet.clock.schedule(update)
💡 Pyglet 2.0+ nutzt eine programmable Pipeline – fixer Legacy-OpenGL (glBegin/glEnd) funktioniert nicht mehr. Alles läuft über Shader und Vertex Buffers. Das ist moderner und schneller.

Pyglet vs Arcade – Wann was?

AspektPyglet 2.1Arcade 3.3
AbstraktionsebeneNiedrig (OpenGL-nah)Hoch (Spielorientiert)
LernkurveSteilerFlacher
Sprites & KollisionManuellEingebaut
PhysikNicht eingebaut3 Engines eingebaut
GUINicht eingebautUIManager eingebaut
Custom Shader✅ Volle Kontrolle⚠️ Eingeschränkt
3D-Unterstützung✅ Möglich❌ Nur 2D
ZielgruppeErfahrene EntwicklerAnfänger bis Fortgeschrittene
LeistungMaximum (direkter GPU-Zugriff)Sehr gut (optimiertes Arcade)
CommunityKlein aber aktivWächst (Education-Fokus)
🎯 Empfehlung: Nutze Arcade für Spiele und Lernprojekte. Nutze Pyglet direkt wenn du maximale Kontrolle über OpenGL brauchst, 3D nutzen willst, oder custom Rendering-Effekte benötigst die Arcade nicht bietet.