Cross-platform library for developing multimedia applications and video games in Python built on top of SDL
Timing control, frame rate management, and animation support for smooth gameplay. Pygame's time module provides essential tools for controlling game timing, measuring elapsed time, and creating consistent frame rates across different hardware.
Get timing information and measure elapsed time.
def get_ticks() -> int:
"""
Get milliseconds since pygame.init() was called.
Returns:
int: Milliseconds elapsed since pygame initialization
"""
def wait(milliseconds: int) -> int:
"""
Pause program execution for specified time.
Args:
milliseconds (int): Time to wait in milliseconds
Returns:
int: Actual time waited (may be slightly different)
"""
def delay(milliseconds: int) -> int:
"""
Pause program with CPU time release (more CPU friendly than wait).
Args:
milliseconds (int): Time to delay in milliseconds
Returns:
int: Actual time delayed
"""Manage game frame rate for consistent gameplay across different hardware.
class Clock:
def __init__(self):
"""Create clock object for frame rate management."""
def tick(self, framerate: int = 0) -> int:
"""
Control frame rate and get frame time.
Args:
framerate (int): Target frames per second (0 for unlimited)
Returns:
int: Milliseconds since last call
"""
def tick_busy_loop(self, framerate: int = 0) -> int:
"""
Accurate frame rate control using busy loop (more CPU intensive).
Args:
framerate (int): Target frames per second
Returns:
int: Milliseconds since last call
"""
def get_time(self) -> int:
"""
Get time since last tick() call.
Returns:
int: Milliseconds since last tick
"""
def get_rawtime(self) -> int:
"""
Get actual time since last tick() (ignoring delays).
Returns:
int: Raw milliseconds since last tick
"""
def get_fps(self) -> float:
"""
Get current frame rate.
Returns:
float: Frames per second averaged over last 10 frames
"""Schedule events to be posted at regular intervals.
def set_timer(eventid: int, milliseconds: int) -> None:
"""
Repeatedly post an event at regular intervals.
Args:
eventid (int): Event type to post
milliseconds (int): Interval in milliseconds (0 to stop)
"""
def set_timer(eventid: int, milliseconds: int, loops: int) -> None:
"""
Post event with limited number of repetitions.
Args:
eventid (int): Event type to post
milliseconds (int): Interval in milliseconds
loops (int): Number of times to post event (0 for infinite)
"""Helper functions and classes for creating smooth animations.
def lerp(start: float, end: float, t: float) -> float:
"""
Linear interpolation between two values.
Args:
start (float): Starting value
end (float): Ending value
t (float): Interpolation factor (0.0 to 1.0)
Returns:
float: Interpolated value
"""
def smooth_step(t: float) -> float:
"""
Smooth interpolation curve (ease in and out).
Args:
t (float): Input value (0.0 to 1.0)
Returns:
float: Smoothed value using 3t² - 2t³
"""
def ease_in_quad(t: float) -> float:
"""
Quadratic ease-in animation curve.
Args:
t (float): Time parameter (0.0 to 1.0)
Returns:
float: Eased value
"""
def ease_out_quad(t: float) -> float:
"""
Quadratic ease-out animation curve.
Args:
t (float): Time parameter (0.0 to 1.0)
Returns:
float: Eased value
"""
def ease_in_out_quad(t: float) -> float:
"""
Quadratic ease-in-out animation curve.
Args:
t (float): Time parameter (0.0 to 1.0)
Returns:
float: Eased value
"""Object-oriented animation system for managing multiple animations.
class Animation:
def __init__(self, start_value: float, end_value: float, duration: int, easing_func = None):
"""
Create animation between two values.
Args:
start_value (float): Starting value
end_value (float): Target value
duration (int): Animation duration in milliseconds
easing_func: Easing function (default: linear)
"""
def update(self, dt: int) -> None:
"""
Update animation progress.
Args:
dt (int): Delta time in milliseconds
"""
def get_value(self) -> float:
"""
Get current animated value.
Returns:
float: Current value based on animation progress
"""
def is_finished(self) -> bool:
"""
Check if animation is complete.
Returns:
bool: True if animation has finished
"""
def reset(self) -> None:
"""Reset animation to beginning."""
def reverse(self) -> None:
"""Reverse animation direction."""
class AnimationManager:
def __init__(self):
"""Manage multiple animations."""
def add_animation(self, name: str, animation: Animation) -> None:
"""
Add animation to manager.
Args:
name (str): Animation identifier
animation (Animation): Animation object
"""
def update_all(self, dt: int) -> None:
"""
Update all managed animations.
Args:
dt (int): Delta time in milliseconds
"""
def get_value(self, name: str) -> float:
"""
Get value of named animation.
Args:
name (str): Animation name
Returns:
float: Current animation value
"""
def remove_finished(self) -> None:
"""Remove all completed animations."""import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
# Create clock for frame rate control
clock = pygame.time.Clock()
FPS = 60
# Game state
player_x = 400
player_speed = 200 # pixels per second
running = True
while running:
# Get delta time in seconds
dt = clock.tick(FPS) / 1000.0
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Frame-rate independent movement
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player_x -= player_speed * dt
if keys[pygame.K_RIGHT]:
player_x += player_speed * dt
# Keep player on screen
player_x = max(0, min(800, player_x))
# Draw
screen.fill((0, 0, 0))
pygame.draw.circle(screen, (255, 255, 255), (int(player_x), 300), 20)
# Display FPS
fps_text = f"FPS: {clock.get_fps():.1f}"
print(fps_text) # In real game, render to screen
pygame.display.flip()
pygame.quit()import pygame
import random
pygame.init()
screen = pygame.display.set_mode((800, 600))
# Create custom events
SPAWN_ENEMY = pygame.event.custom_type()
FLASH_SCREEN = pygame.event.custom_type()
GAME_TIMER = pygame.event.custom_type()
# Set up timers
pygame.time.set_timer(SPAWN_ENEMY, 2000) # Spawn enemy every 2 seconds
pygame.time.set_timer(FLASH_SCREEN, 500) # Flash every 0.5 seconds
pygame.time.set_timer(GAME_TIMER, 1000) # Game timer every second
# Game state
enemies = []
flash_color = (0, 0, 0)
game_time = 0
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == SPAWN_ENEMY:
# Spawn enemy at random position
enemy_pos = (random.randint(0, 800), random.randint(0, 600))
enemies.append(enemy_pos)
print(f"Enemy spawned at {enemy_pos}")
elif event.type == FLASH_SCREEN:
# Toggle flash color
flash_color = (50, 0, 0) if flash_color == (0, 0, 0) else (0, 0, 0)
elif event.type == GAME_TIMER:
# Update game timer
game_time += 1
print(f"Game time: {game_time} seconds")
# Stop spawning after 10 seconds
if game_time >= 10:
pygame.time.set_timer(SPAWN_ENEMY, 0) # Stop timer
# Draw
screen.fill(flash_color)
# Draw enemies
for enemy_pos in enemies:
pygame.draw.circle(screen, (255, 0, 0), enemy_pos, 15)
# Draw timer
font = pygame.font.Font(None, 36)
timer_text = font.render(f"Time: {game_time}", True, (255, 255, 255))
screen.blit(timer_text, (50, 50))
pygame.display.flip()
clock.tick(60)
pygame.quit()import pygame
import math
# Easing functions
def ease_in_quad(t):
return t * t
def ease_out_quad(t):
return 1 - (1 - t) * (1 - t)
def ease_in_out_quad(t):
if t < 0.5:
return 2 * t * t
else:
return 1 - 2 * (1 - t) * (1 - t)
def ease_in_bounce(t):
return 1 - ease_out_bounce(1 - t)
def ease_out_bounce(t):
if t < 1 / 2.75:
return 7.5625 * t * t
elif t < 2 / 2.75:
t -= 1.5 / 2.75
return 7.5625 * t * t + 0.75
elif t < 2.5 / 2.75:
t -= 2.25 / 2.75
return 7.5625 * t * t + 0.9375
else:
t -= 2.625 / 2.75
return 7.5625 * t * t + 0.984375
class Animation:
def __init__(self, start_value, end_value, duration, easing_func=None):
self.start_value = start_value
self.end_value = end_value
self.duration = duration
self.easing_func = easing_func or (lambda t: t) # Linear by default
self.elapsed = 0
self.finished = False
def update(self, dt):
if not self.finished:
self.elapsed += dt
if self.elapsed >= self.duration:
self.elapsed = self.duration
self.finished = True
def get_value(self):
if self.duration == 0:
return self.end_value
t = self.elapsed / self.duration
eased_t = self.easing_func(t)
return self.start_value + (self.end_value - self.start_value) * eased_t
def is_finished(self):
return self.finished
def reset(self):
self.elapsed = 0
self.finished = False
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
# Create animations
animations = {
'x': Animation(100, 700, 2000, ease_out_bounce), # X movement with bounce
'y': Animation(100, 500, 1500, ease_in_out_quad), # Y movement smooth
'size': Animation(10, 50, 1000, ease_in_quad), # Size growth
'rotation': Animation(0, 360, 3000), # Rotation
}
# Animation state
running = True
animation_started = False
start_time = 0
while running:
dt = clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# Reset and start animations
for anim in animations.values():
anim.reset()
animation_started = True
# Update animations
if animation_started:
for anim in animations.values():
anim.update(dt)
# Get current values
x = animations['x'].get_value()
y = animations['y'].get_value()
size = animations['size'].get_value()
rotation = animations['rotation'].get_value()
# Draw
screen.fill((0, 0, 0))
# Draw animated circle
pygame.draw.circle(screen, (255, 255, 255), (int(x), int(y)), int(size))
# Draw rotating line from circle
line_length = size * 2
end_x = x + line_length * math.cos(math.radians(rotation))
end_y = y + line_length * math.sin(math.radians(rotation))
pygame.draw.line(screen, (255, 0, 0), (x, y), (end_x, end_y), 3)
# Draw instructions
font = pygame.font.Font(None, 36)
text = font.render("Press SPACE to start animation", True, (255, 255, 255))
screen.blit(text, (50, 50))
# Show animation progress
all_finished = all(anim.is_finished() for anim in animations.values())
if animation_started:
progress_text = "Animation finished!" if all_finished else "Animating..."
progress = font.render(progress_text, True, (255, 255, 0))
screen.blit(progress, (50, 100))
pygame.display.flip()
pygame.quit()import pygame
import random
import math
class Particle:
def __init__(self, x, y):
self.x = x
self.y = y
self.vel_x = random.uniform(-100, 100) # pixels per second
self.vel_y = random.uniform(-200, -50) # upward bias
self.life = random.uniform(2.0, 4.0) # seconds
self.max_life = self.life
self.size = random.uniform(2, 6)
self.color = [255, random.randint(100, 255), 0] # Orange-ish
def update(self, dt):
# Physics (time-based)
gravity = 200 # pixels per second squared
self.vel_y += gravity * dt
# Update position
self.x += self.vel_x * dt
self.y += self.vel_y * dt
# Update life
self.life -= dt
# Fade out as life decreases
life_ratio = self.life / self.max_life
self.color[0] = int(255 * life_ratio)
self.color[1] = int(self.color[1] * life_ratio)
def is_dead(self):
return self.life <= 0
def draw(self, screen):
if self.life > 0:
pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), int(self.size * (self.life / self.max_life)))
class ParticleSystem:
def __init__(self):
self.particles = []
self.spawn_timer = 0
self.spawn_rate = 0.1 # seconds between spawns
def update(self, dt, mouse_pos):
# Spawn particles
self.spawn_timer -= dt
if self.spawn_timer <= 0:
# Spawn particle at mouse position
self.particles.append(Particle(mouse_pos[0], mouse_pos[1]))
self.spawn_timer = self.spawn_rate
# Update particles
for particle in self.particles[:]:
particle.update(dt)
if particle.is_dead() or particle.y > 700: # Remove if dead or off-screen
self.particles.remove(particle)
def draw(self, screen):
for particle in self.particles:
particle.draw(screen)
def get_count(self):
return len(self.particles)
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
particle_system = ParticleSystem()
font = pygame.font.Font(None, 36)
running = True
while running:
dt = clock.tick(60) / 1000.0 # Convert to seconds
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
mouse_pos = pygame.mouse.get_pos()
# Update particle system
particle_system.update(dt, mouse_pos)
# Draw
screen.fill((0, 0, 30)) # Dark blue background
# Draw particle system
particle_system.draw(screen)
# Draw UI
particle_count = font.render(f"Particles: {particle_system.get_count()}", True, (255, 255, 255))
screen.blit(particle_count, (10, 10))
fps_text = font.render(f"FPS: {clock.get_fps():.1f}", True, (255, 255, 255))
screen.blit(fps_text, (10, 50))
instructions = font.render("Move mouse to emit particles", True, (255, 255, 255))
screen.blit(instructions, (10, 90))
pygame.display.flip()
pygame.quit()import pygame
import math
pygame.init()
screen = pygame.display.set_mode((800, 600))
font = pygame.font.Font(None, 36)
# Two circles - one frame-dependent, one time-dependent
circle1_angle = 0 # Frame-dependent rotation
circle2_angle = 0 # Time-dependent rotation
rotation_speed_degrees_per_second = 90 # 90 degrees per second
clock = pygame.time.Clock()
target_fps = 60
actual_fps_limit = 60 # Can be changed to test different frame rates
running = True
while running:
dt = clock.tick(actual_fps_limit) / 1000.0 # Delta time in seconds
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
actual_fps_limit = 30
elif event.key == pygame.K_2:
actual_fps_limit = 60
elif event.key == pygame.K_3:
actual_fps_limit = 120
# Frame-dependent rotation (BAD - speed depends on frame rate)
circle1_angle += 1.5 # Fixed increment per frame
# Time-dependent rotation (GOOD - consistent speed regardless of frame rate)
circle2_angle += rotation_speed_degrees_per_second * dt
# Calculate positions
center_x = 400
radius = 150
circle1_x = center_x - 100 + radius * math.cos(math.radians(circle1_angle))
circle1_y = 300 + radius * math.sin(math.radians(circle1_angle))
circle2_x = center_x + 100 + radius * math.cos(math.radians(circle2_angle))
circle2_y = 300 + radius * math.sin(math.radians(circle2_angle))
# Draw
screen.fill((0, 0, 0))
# Draw orbits
pygame.draw.circle(screen, (50, 50, 50), (center_x - 100, 300), radius, 2)
pygame.draw.circle(screen, (50, 50, 50), (center_x + 100, 300), radius, 2)
# Draw centers
pygame.draw.circle(screen, (100, 100, 100), (center_x - 100, 300), 5)
pygame.draw.circle(screen, (100, 100, 100), (center_x + 100, 300), 5)
# Draw rotating circles
pygame.draw.circle(screen, (255, 100, 100), (int(circle1_x), int(circle1_y)), 15) # Red - frame-dependent
pygame.draw.circle(screen, (100, 255, 100), (int(circle2_x), int(circle2_y)), 15) # Green - time-dependent
# Labels
label1 = font.render("Frame-dependent (RED)", True, (255, 100, 100))
screen.blit(label1, (50, 50))
label2 = font.render("Time-dependent (GREEN)", True, (100, 255, 100))
screen.blit(label2, (450, 50))
# FPS info
fps_text = font.render(f"FPS: {clock.get_fps():.1f}", True, (255, 255, 255))
screen.blit(fps_text, (50, 500))
instructions = font.render("Press 1 (30fps), 2 (60fps), 3 (120fps)", True, (255, 255, 255))
screen.blit(instructions, (50, 530))
explanation = font.render("Green circle maintains consistent speed at any FPS", True, (255, 255, 255))
screen.blit(explanation, (50, 560))
pygame.display.flip()
pygame.quit()