Cross-platform windowing and multimedia library for Python with OpenGL graphics, event handling, and audio/video playback
Application lifecycle management, event loop control, and timing/scheduling system.
# Start event loop
pyglet.app.run() # Blocks until exit
pyglet.app.exit() # Stop the loop
# Schedule functions
pyglet.clock.schedule(update_func) # Every frame
pyglet.clock.schedule_interval(update_func, 1/60) # Fixed rate
pyglet.clock.schedule_once(delayed_func, 3.0) # One-time delay
pyglet.clock.unschedule(update_func) # Remove scheduled
# Manual timing
dt = pyglet.clock.tick() # Returns delta time
fps = pyglet.clock.get_fps() # Current FPS estimatedef pyglet.app.run(interval=1/60):
"""Start event loop. Blocks until pyglet.app.exit() or all windows closed."""
def pyglet.app.exit():
"""Exit the event loop."""
# Global objects
pyglet.app.event_loop: EventLoop
pyglet.app.windows: weakref.WeakSet # All open windowsAll scheduled functions must accept dt parameter:
def update(dt): # dt = delta time in seconds
player.x += velocity * dt# Every frame (variable timing)
pyglet.clock.schedule(func)
# Use for: Animation, visual effects, input polling
# Fixed interval (consistent timing)
pyglet.clock.schedule_interval(func, interval_seconds)
# Use for: Physics, game logic, spawning
# Approximate interval (drift allowed)
pyglet.clock.schedule_interval_soft(func, interval_seconds)
# Use for: Autosave, garbage collection, non-critical tasks
# One-time delay
pyglet.clock.schedule_once(func, delay_seconds)
# Use for: Delayed actions, cooldowns, timers
# Remove scheduled function
pyglet.clock.unschedule(func)def spawn_enemy(dt, enemy_type, x, y):
enemies.append(Enemy(enemy_type, x, y))
pyglet.clock.schedule_once(spawn_enemy, 2.0,
enemy_type='zombie', x=100, y=200)import pyglet
window = pyglet.window.Window()
batch = pyglet.graphics.Batch()
# Setup
player = Player(batch)
enemies = []
# Update function
def update(dt):
"""Game logic - called 60 times per second"""
player.update(dt)
for enemy in enemies:
enemy.update(dt)
check_collisions()
# Render function
@window.event
def on_draw():
"""Rendering - called when needed"""
window.clear()
batch.draw()
# Schedule
pyglet.clock.schedule_interval(update, 1/60)
# Run
pyglet.app.run()class Player:
def __init__(self):
self.x = 0
self.velocity_x = 100 # pixels per second (not per frame!)
def update(self, dt):
# CORRECT: velocity * dt
self.x += self.velocity_x * dt
# WRONG: velocity without dt (frame-rate dependent!)
# self.x += self.velocity_x# Fast physics update
def update_physics(dt):
physics.step(dt)
# Slower AI update
def update_ai(dt):
for enemy in enemies:
enemy.think()
# Very slow autosave
def autosave(dt):
save_game()
pyglet.clock.schedule_interval(update_physics, 1/120) # 120 Hz
pyglet.clock.schedule_interval(update_ai, 1/10) # 10 Hz
pyglet.clock.schedule_interval(autosave, 60.0) # Every minuteclass Timer:
"""Reusable countdown timer"""
def __init__(self, duration, callback):
self.duration = duration
self.callback = callback
self.elapsed = 0
self.active = False
def start(self):
self.elapsed = 0
self.active = True
pyglet.clock.schedule(self.update)
def update(self, dt):
if not self.active:
return
self.elapsed += dt
if self.elapsed >= self.duration:
self.stop()
self.callback()
def stop(self):
self.active = False
pyglet.clock.unschedule(self.update)
# Usage
timer = Timer(3.0, lambda: print("Time's up!"))
timer.start()class GameScheduler:
def __init__(self):
self.funcs = [] # [(func, interval), ...]
self.paused = False
def schedule(self, func, interval=None):
self.funcs.append((func, interval))
if not self.paused:
self._schedule_func(func, interval)
def _schedule_func(self, func, interval):
if interval is None:
pyglet.clock.schedule(func)
else:
pyglet.clock.schedule_interval(func, interval)
def pause(self):
if not self.paused:
for func, _ in self.funcs:
pyglet.clock.unschedule(func)
self.paused = True
def resume(self):
if self.paused:
for func, interval in self.funcs:
self._schedule_func(func, interval)
self.paused = Falseclass pyglet.clock.Clock:
time: float # Current time
@staticmethod
def sleep(microseconds: float)
def tick(poll=False) -> float # Update and return dt
def get_frequency() -> float # Clock update frequency# Method 1: Use vsync (recommended)
window = pyglet.window.Window(vsync=True) # Syncs to monitor
# Method 2: Custom interval
pyglet.app.run(interval=1/60) # Cap at 60 FPS# CORRECT
def update(dt):
player.x += velocity * dt
# WRONG - will crash
def update():
player.x += velocity# CORRECT: Frame-rate independent
x += velocity * dt
# WRONG: Frame-rate dependent
x += velocity# CORRECT
def cleanup():
pyglet.clock.unschedule(update_func)
# WRONG: Memory leak
# (never unscheduling)# WRONG: Scheduled multiple times
@window.event
def on_draw():
pyglet.clock.schedule_once(foo, 1.0) # BAD!
window.clear()
batch.draw()
# CORRECT: Schedule outside
pyglet.clock.schedule_once(foo, 1.0)# Physics/game logic: Use schedule_interval (consistent timing)
pyglet.clock.schedule_interval(update_physics, 1/60)
# Animation/visual: Use schedule (smooth, every frame)
pyglet.clock.schedule(update_animation)
# Non-critical periodic: Use schedule_interval_soft (CPU efficient)
pyglet.clock.schedule_interval_soft(cleanup, 10.0)# Get current FPS
fps = pyglet.clock.get_fps()
print(f"FPS: {fps:.1f}")
# Get clock frequency
freq = pyglet.clock.get_frequency()
# Access clock directly
clock = pyglet.clock.get_default()
current_time = clock.time()| Mistake | Problem | Solution |
|---|---|---|
| Forget dt parameter | Crash | Always: def update(dt): |
| Don't multiply by dt | Frame-rate dependent | Always: x += velocity * dt |
| Never unschedule | Memory leak | Call unschedule() when done |
| Schedule in on_draw | Multiple schedules | Schedule outside on_draw |
| Wrong schedule type | Inconsistent behavior | schedule_interval for physics |
window = pyglet.window.Window()
running = True
while running:
window.dispatch_events() # Process events
dt = pyglet.clock.tick() # Update clock
# Call scheduled functions
pyglet.clock.get_default().call_scheduled_functions(dt)
# Custom logic here
# ...
# Render
window.dispatch_event('on_draw')
window.flip()Next Steps: See windowing.md for window events, sprites-shapes.md for rendering.
Install with Tessl CLI
npx tessl i tessl/pypi-pyglet