Pygame
Python game development library.
Overview
Pygame is a set of Python modules designed for writing video games. It provides functionality for creating graphics, handling input, playing sounds, and more.
Key Features:
- 2D graphics and sprites
- Event handling
- Sound and music playback
- Font rendering
- Collision detection
- Game loops
- Hardware acceleration
Installation
pip install pygame
# With additional features
pip install pygame[fonts]
Getting Started
Basic Window
import pygame
import sys
# Initialize pygame
pygame.init()
# Create window
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("My Game")
# Game loop
running = True
while running:
# Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# Drawing
screen.fill((0, 0, 0)) # Black background
pygame.draw.rect(screen, (255, 0, 0), (100, 100, 50, 50))
# Update display
pygame.display.flip()
# Quit pygame
pygame.quit()
sys.exit()
Drawing
Colors
# RGB colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
CYAN = (0, 255, 255)
MAGENTA = (255, 0, 255)
# With alpha (RGBA)
TRANSPARENT = (0, 0, 0, 0)
SEMI_RED = (255, 0, 0, 128)
Shapes
# Rectangle
pygame.draw.rect(screen, RED, (x, y, width, height))
pygame.draw.rect(screen, RED, (x, y, width, height), 2) # Outline
# Circle
pygame.draw.circle(screen, GREEN, (center_x, center_y), radius)
pygame.draw.circle(screen, GREEN, (cx, cy, radius), 2) # Outline
# Line
pygame.draw.line(screen, BLUE, (x1, y1), (x2, y2), width)
pygame.draw.aaline(screen, BLUE, (x1, y1), (x2, y2)) # Antialiased
# Polygon
points = [(x1, y1), (x2, y2), (x3, y3)]
pygame.draw.polygon(screen, YELLOW, points)
pygame.draw.polygon(screen, YELLOW, points, 2) # Outline
# Ellipse
pygame.draw.ellipse(screen, MAGENTA, (x, y, width, height))
# Arc
pygame.draw.arc(screen, CYAN, (x, y, width, height), start_angle, end_angle)
# Lines (multiple)
points = [(0, 0), (100, 100), (200, 0)]
pygame.draw.lines(screen, WHITE, False, points, 2)
Surfaces
# Create surface
surface = pygame.Surface((width, height))
surface = pygame.Surface((width, height), pygame.SRCALPHA) # With alpha
# Fill
surface.fill(RED)
surface.fill((0, 0, 0, 128), pygame.Rect(0, 0, 100, 100)) # Partially
# Blit (copy one surface to another)
screen.blit(surface, (x, y))
# Transform
scaled = pygame.transform.scale(surface, (new_width, new_height))
rotated = pygame.transform.rotate(surface, angle)
flipped = pygame.transform.flip(surface, flip_x, flip_y)
Sprites
Sprite Class
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.speed = 5
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.rect.x -= self.speed
if keys[pygame.K_RIGHT]:
self.rect.x += self.speed
if keys[pygame.K_UP]:
self.rect.y -= self.speed
if keys[pygame.K_DOWN]:
self.rect.y += self.speed
def draw(self, screen):
screen.blit(self.image, self.rect)
# Usage
player = Player(100, 100)
all_sprites.add(player)
all_sprites.draw(screen)
Sprite Groups
# Create groups
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
# Add to groups
player = Player(100, 100)
all_sprites.add(player)
enemies.add(enemy1, enemy2)
# Update all sprites
all_sprites.update()
# Draw all sprites
all_sprites.draw(screen)
# Remove from groups
player.kill()
# Check group membership
if player in all_sprites:
print("Player is alive")
Loading Images
# Load image
image = pygame.image.load("sprite.png")
# Load with transparency
image = pygame.image.load("sprite.png").convert_alpha()
# Convert for faster blitting
image = image.convert() # Without alpha
image = image.convert_alpha() # With alpha
# Load from string
import io
image = pygame.image.load(io.BytesIO(image_data))
Events
Event Types
for event in pygame.event.get():
# Quit
if event.type == pygame.QUIT:
running = False
# Key pressed
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print("Space pressed")
if event.key == pygame.K_ESCAPE:
running = False
# Key released
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
print("Space released")
# Mouse clicked
if event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
button = event.button
if button == 1: # Left click
print(f"Left click at {x}, {y}")
# Mouse motion
if event.type == pygame.MOUSEMOTION:
x, y = event.pos
rel_x, rel_y = event.rel
# Joystick events
if event.type == pygame.JOYBUTTONDOWN:
if event.button == 0: # A button
print("Joystick A pressed")
# Window events
if event.type == pygame.WINDOWFOCUSLOST:
print("Window lost focus")
if event.type == pygame.WINDOWRESIZED:
print(f"Window resized to {event.x}x{event.y}")
Input States
# Keyboard state
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
print("Space is held down")
# Mouse state
mouse_pos = pygame.mouse.get_pos()
mouse_buttons = pygame.mouse.get_pressed()
if mouse_buttons[0]: # Left button
print("Left mouse button held")
# Joystick state
joystick = pygame.joystick.Joystick(0)
axes = joystick.get_numaxes()
for i in range(axes):
value = joystick.get_axis(i)
Collision Detection
# Rectangle collision
if pygame.sprite.collide_rect(sprite1, sprite2):
print("Collision!")
# Group collision
hits = pygame.sprite.spritecollide(player, enemies, True) # Kill enemies
for enemy in hits:
score += 10
# Group vs group
pygame.sprite.groupcollide(bullets, enemies, True, True) # Kill both
# Circle collision (requires radius attribute)
pygame.sprite.collide_circle(sprite1, sprite2)
# Group circle collision
pygame.sprite.spritecollide(player, enemies, True, pygame.sprite.collide_circle)
# Mask collision (pixel-perfect)
mask1 = pygame.mask.from_surface(sprite1.image)
mask2 = pygame.mask.from_surface(sprite2.image)
if sprite1.rect.colliderect(sprite2.rect): # First check bounding
offset = (sprite2.rect.x - sprite1.rect.x, sprite2.rect.y - sprite1.rect.y)
if mask1.overlap(mask2, offset):
print("Pixel-perfect collision!")
Sound
# Initialize mixer
pygame.mixer.init()
# Load sound
shoot_sound = pygame.mixer.Sound("shoot.wav")
explosion_sound = pygame.mixer.Sound("explosion.wav")
# Set volume
shoot_sound.set_volume(0.5)
explosion_sound.set_volume(0.8)
# Play sound
shoot_sound.play()
shoot_sound.play(maxtime=500) # Stop after 500ms
# Load music (streaming)
pygame.mixer.music.load("bgm.mp3")
pygame.mixer.music.play(-1) # Loop forever
pygame.mixer.music.pause()
pygame.mixer.music.unpause()
pygame.mixer.music.stop()
# Music volume
pygame.mixer.music.set_volume(0.5)
Fonts
# Initialize font system
pygame.font.init()
# Get default font
font = pygame.font.Font(None, 36) # Default system font, size 36
# Load custom font
font = pygame.font.Font("custom.ttf", 36)
# Render text
text_surface = font.render("Hello, World!", True, WHITE) # Antialiased
text_surface = font.render("Hello", False, RED) # Not antialiased
# Get text size
width, height = font.size("Hello")
# Draw text on screen
screen.blit(text_surface, (x, y))
Time and Delta Time
import pygame
import time
# Clock
clock = pygame.time.Clock()
# Set framerate
clock.tick(60) # 60 FPS
fps = clock.get_fps()
# Delta time (for consistent movement)
last_time = time.time()
while True:
dt = time.time() - last_time
last_time = time.time()
# Move at consistent speed regardless of framerate
player.x += player.speed * dt
Camera
class Camera:
def __init__(self, width, height):
self.camera = pygame.Rect(0, 0, width, height)
self.width = width
self.height = height
def apply(self, entity):
return entity.rect.move(self.camera.topleft)
def apply_rect(self, rect):
return rect.move(self.camera.topleft)
def update(self, target):
x = -target.rect.x + int(SCREEN_WIDTH / 2)
y = -target.rect.y + int(SCREEN_HEIGHT / 2)
# Limit scrolling to map size
x = min(0, x)
y = min(0, y)
x = max(-(self.width - SCREEN_WIDTH), x)
y = max(-(self.height - SCREEN_HEIGHT), y)
self.camera = pygame.Rect(x, y, self.width, self.height)
# Usage
camera = Camera(map_width, map_height)
for entity in all_sprites:
screen.blit(entity.image, camera.apply(entity))
UI Elements
Button
class Button:
def __init__(self, x, y, width, height, text, callback):
self.rect = pygame.Rect(x, y, width, height)
self.text = text
self.callback = callback
self.color = (100, 100, 100)
self.hover_color = (150, 150, 150)
self.font = pygame.font.Font(None, 36)
def handle_event(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and self.rect.collidepoint(event.pos):
self.callback()
def draw(self, screen):
mouse_pos = pygame.mouse.get_pos()
color = self.hover_color if self.rect.collidepoint(mouse_pos) else self.color
pygame.draw.rect(screen, color, self.rect)
pygame.draw.rect(screen, WHITE, self.rect, 2) # Border
text_surface = self.font.render(self.text, True, WHITE)
text_rect = text_surface.get_rect(center=self.rect.center)
screen.blit(text_surface, text_rect)
Best Practices
1. Use Sprite Groups
# Good: Use groups for efficient updates
all_sprites = pygame.sprite.Group()
all_sprites.update() # Updates all sprites
all_sprites.draw(screen) # Draws all sprites
2. Delta Time
# Good: Frame-rate independent movement
player.x += speed * dt
3. Pre-load Resources
# Good: Load images/sounds once at startup
def load_game():
global player_image, enemy_image, shoot_sound
player_image = pygame.image.load("player.png").convert_alpha()
enemy_image = pygame.image.load("enemy.png").convert_alpha()
shoot_sound = pygame.mixer.Sound("shoot.wav")
4. Clean Exit
# Good: Proper cleanup
try:
game_loop()
finally:
pygame.quit()
sys.exit()
Game Loop Template
import pygame
import sys
class Game:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((800, 600))
self.clock = pygame.time.Clock()
self.running = True
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
def update(self):
pass
def draw(self):
self.screen.fill((0, 0, 0))
pygame.display.flip()
def run(self):
while self.running:
dt = self.clock.tick(60) / 1000.0 # Delta time in seconds
self.handle_events()
self.update()
self.draw()
pygame.quit()
sys.exit()
if __name__ == "__main__":
game = Game()
game.run()
References
- Official Documentation: https://www.pygame.org/docs/
- Pygame Wiki: https://www.pygame.org/wiki/
- KidsCanCode Pygame Tutorials: https://kidscancode.org/pygame_tutorials/