Python Game Development library providing comprehensive multimedia functionality for creating games and interactive applications.
—
High-level game object management with sprite classes, collision detection, and group operations. Provides organized structure for managing game entities and their interactions.
The Sprite class provides the foundation for all visible game objects.
class Sprite:
def __init__(self):
"""
Initialize sprite object.
Must set image and rect attributes after creation.
"""
image: Surface # Sprite's visual representation
rect: Rect # Sprite's position and collision bounds
def update(self, *args, **kwargs) -> None:
"""
Update sprite state.
Override this method in subclasses for custom behavior.
Parameters:
*args: Variable arguments passed from group update
**kwargs: Keyword arguments passed from group update
"""
def add(self, *groups: Group) -> None:
"""
Add sprite to groups.
Parameters:
*groups: Groups to add sprite to
"""
def remove(self, *groups: Group) -> None:
"""
Remove sprite from groups.
Parameters:
*groups: Groups to remove sprite from
"""
def kill(self) -> None:
"""Remove sprite from all groups."""
def alive(self) -> bool:
"""
Check if sprite belongs to any groups.
Returns:
bool: True if sprite is in at least one group
"""
def groups(self) -> list[Group]:
"""
Get list of groups containing this sprite.
Returns:
list[Group]: Groups this sprite belongs to
"""Enhanced sprite with dirty rectangle tracking for optimized rendering.
class DirtySprite(Sprite):
def __init__(self):
"""Initialize dirty sprite with additional attributes."""
dirty: int = 1 # Dirty flag (0=clean, 1=dirty, 2=always dirty)
source_rect: Rect | None = None # Source rectangle for partial image blitting
visible: int = 1 # Visibility flag (0=invisible, 1=visible)
blendmode: int = 0 # Blend mode for renderingGroups provide containers for managing collections of sprites.
class Group:
def __init__(self, *sprites: Sprite):
"""
Initialize group with optional sprites.
Parameters:
*sprites: Initial sprites to add to group
"""
def sprites(self) -> list[Sprite]:
"""
Get list of sprites in group.
Returns:
list[Sprite]: Sprites in this group
"""
def copy(self) -> Group:
"""
Create copy of group.
Returns:
Group: New group with same sprites
"""
def add(self, *sprites: Sprite) -> None:
"""
Add sprites to group.
Parameters:
*sprites: Sprites to add
"""
def remove(self, *sprites: Sprite) -> None:
"""
Remove sprites from group.
Parameters:
*sprites: Sprites to remove
"""
def has(self, *sprites: Sprite) -> bool:
"""
Check if group contains sprites.
Parameters:
*sprites: Sprites to check for
Returns:
bool: True if all sprites are in group
"""
def update(self, *args, **kwargs) -> None:
"""
Call update() on all sprites in group.
Parameters:
*args: Arguments to pass to sprite update methods
**kwargs: Keyword arguments to pass to sprite update methods
"""
def draw(self, surface: Surface) -> list[Rect]:
"""
Draw all sprites to surface.
Parameters:
surface: Surface to draw sprites on
Returns:
list[Rect]: List of rectangles that were drawn
"""
def clear(self, surface: Surface, background: Surface | Color) -> list[Rect]:
"""
Clear sprites from surface using background.
Parameters:
surface: Surface to clear sprites from
background: Background to use for clearing
Returns:
list[Rect]: List of rectangles that were cleared
"""
def empty(self) -> None:
"""Remove all sprites from group."""
def __len__(self) -> int:
"""Get number of sprites in group."""
def __iter__(self):
"""Iterate over sprites in group."""
def __contains__(self, sprite: Sprite) -> bool:
"""Check if sprite is in group."""Enhanced group classes with additional functionality.
class RenderUpdates(Group):
"""Group that tracks dirty rectangles for efficient rendering."""
def draw(self, surface: Surface) -> list[Rect]:
"""
Draw sprites and return changed rectangles.
Parameters:
surface: Surface to draw on
Returns:
list[Rect]: Rectangles that changed
"""
class OrderedUpdates(RenderUpdates):
"""RenderUpdates that maintains sprite order."""
def add(self, *sprites: Sprite) -> None:
"""Add sprites maintaining order."""
def remove(self, *sprites: Sprite) -> None:
"""Remove sprites maintaining order."""
class LayeredUpdates(Group):
"""Group with layered rendering support."""
def add(self, *sprites: Sprite, **kwargs) -> None:
"""
Add sprites to specific layer.
Parameters:
*sprites: Sprites to add
**kwargs: Can include 'layer' parameter
"""
def change_layer(self, sprite: Sprite, new_layer: int) -> None:
"""
Move sprite to different layer.
Parameters:
sprite: Sprite to move
new_layer: Target layer
"""
def get_layer_of_sprite(self, sprite: Sprite) -> int:
"""
Get layer of sprite.
Parameters:
sprite: Sprite to check
Returns:
int: Layer number
"""
def get_top_layer(self) -> int:
"""Get highest layer number."""
def get_bottom_layer(self) -> int:
"""Get lowest layer number."""
def move_to_front(self, sprite: Sprite) -> None:
"""Move sprite to front (highest layer)."""
def move_to_back(self, sprite: Sprite) -> None:
"""Move sprite to back (lowest layer)."""
def get_top_sprite(self) -> Sprite | None:
"""Get topmost sprite."""
def get_sprites_at(self, pos: tuple[int, int]) -> list[Sprite]:
"""
Get sprites at position.
Parameters:
pos: (x, y) position to check
Returns:
list[Sprite]: Sprites at position, ordered by layer
"""
def layers(self) -> list[int]:
"""Get list of all layers."""
def draw(self, surface: Surface) -> list[Rect]:
"""Draw sprites in layer order."""
class LayeredDirty(LayeredUpdates):
"""LayeredUpdates with dirty rectangle optimization."""
def draw(self, surface: Surface, bgd: Surface | None = None) -> list[Rect]:
"""
Draw only dirty sprites.
Parameters:
surface: Surface to draw on
bgd: Background surface for clearing
Returns:
list[Rect]: Changed rectangles
"""
def clear(self, surface: Surface, bgd: Surface) -> None:
"""Clear dirty sprites using background."""
def repaint_rect(self, screen_rect: Rect) -> None:
"""Mark screen area as needing repaint."""
def set_clip(self, screen_rect: Rect | None = None) -> None:
"""Set clipping rectangle for drawing."""
class GroupSingle(Group):
"""Group that contains only one sprite."""
sprite: Sprite | None # The single sprite in the group
def __init__(self, sprite: Sprite | None = None):
"""
Initialize single sprite group.
Parameters:
sprite: Initial sprite (optional)
"""Functions for detecting collisions between sprites and groups.
def spritecollide(sprite: Sprite, group: Group, dokill: bool, collided: callable | None = None) -> list[Sprite]:
"""
Find sprites in group that collide with sprite.
Parameters:
sprite: Sprite to test collision against
group: Group of sprites to check
dokill: If True, remove colliding sprites from group
collided: Custom collision function (default uses rect collision)
Returns:
list[Sprite]: Sprites that collided
"""
def groupcollide(group1: Group, group2: Group, dokill1: bool, dokill2: bool, collided: callable | None = None) -> dict[Sprite, list[Sprite]]:
"""
Find collisions between two groups.
Parameters:
group1: First group
group2: Second group
dokill1: Remove colliding sprites from group1
dokill2: Remove colliding sprites from group2
collided: Custom collision function
Returns:
dict[Sprite, list[Sprite]]: Mapping of group1 sprites to colliding group2 sprites
"""
def spritecollideany(sprite: Sprite, group: Group, collided: callable | None = None) -> Sprite | None:
"""
Check if sprite collides with any sprite in group.
Parameters:
sprite: Sprite to test
group: Group to check against
collided: Custom collision function
Returns:
Sprite | None: First colliding sprite or None
"""Built-in collision detection functions.
def collide_rect(left: Sprite, right: Sprite) -> bool:
"""
Rectangle collision detection.
Parameters:
left: First sprite
right: Second sprite
Returns:
bool: True if rectangles overlap
"""
def collide_rect_ratio(ratio: float) -> callable:
"""
Create rectangle collision function with size ratio.
Parameters:
ratio: Size ratio (1.0 = normal, 0.5 = half size, 2.0 = double size)
Returns:
callable: Collision function
"""
def collide_circle(left: Sprite, right: Sprite) -> bool:
"""
Circle collision detection using sprite radius.
Parameters:
left: First sprite (must have radius attribute)
right: Second sprite (must have radius attribute)
Returns:
bool: True if circles overlap
"""
def collide_circle_ratio(ratio: float) -> callable:
"""
Create circle collision function with radius ratio.
Parameters:
ratio: Radius ratio
Returns:
callable: Collision function
"""
def collide_mask(left: Sprite, right: Sprite) -> tuple[int, int] | None:
"""
Pixel-perfect collision using sprite masks.
Parameters:
left: First sprite (must have mask attribute)
right: Second sprite (must have mask attribute)
Returns:
tuple[int, int] | None: Collision point or None
"""import pygame
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50, 50))
self.image.fill((0, 128, 255)) # Blue
self.rect = self.image.get_rect()
self.rect.center = (400, 300)
self.speed = 5
def update(self):
# Handle input
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
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((30, 30))
self.image.fill((255, 0, 0)) # Red
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.speed = 2
def update(self):
# Simple movement
self.rect.x += self.speed
if self.rect.right > 800 or self.rect.left < 0:
self.speed = -self.speed
# Create sprites
player = Player()
enemy1 = Enemy(100, 100)
enemy2 = Enemy(200, 200)
# Create groups
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
all_sprites.add(player, enemy1, enemy2)
enemies.add(enemy1, enemy2)
# Game loop
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Update all sprites
all_sprites.update()
# Check collisions
hits = pygame.sprite.spritecollide(player, enemies, False)
if hits:
print("Player hit enemy!")
# Draw everything
screen.fill((0, 0, 0))
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()import pygame
class Background(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((800, 600))
self.image.fill((0, 100, 0)) # Green background
self.rect = self.image.get_rect()
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50, 50))
self.image.fill((0, 0, 255)) # Blue player
self.rect = self.image.get_rect(center=(400, 300))
class Overlay(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((200, 100))
self.image.fill((255, 255, 0)) # Yellow overlay
self.image.set_alpha(128) # Semi-transparent
self.rect = self.image.get_rect(topleft=(10, 10))
# Create layered group
layered_group = pygame.sprite.LayeredUpdates()
# Add sprites to different layers
background = Background()
player = Player()
overlay = Overlay()
layered_group.add(background, layer=0) # Background layer
layered_group.add(player, layer=1) # Player layer
layered_group.add(overlay, layer=2) # UI layer
# Game loop
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Update and draw in layer order
layered_group.update()
layered_group.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()import pygame
import math
class CircleSprite(pygame.sprite.Sprite):
def __init__(self, x, y, radius, color):
super().__init__()
self.radius = radius
# Create circular image
self.image = pygame.Surface((radius * 2, radius * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, color, (radius, radius), radius)
self.rect = self.image.get_rect(center=(x, y))
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((10, 20))
self.image.fill((255, 255, 0)) # Yellow bullet
self.rect = self.image.get_rect(center=(x, y))
self.speed = 10
def update(self):
self.rect.y -= self.speed
if self.rect.bottom < 0:
self.kill()
# Create sprites
player = CircleSprite(400, 500, 25, (0, 0, 255))
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
# Add enemies
for i in range(5):
enemy = CircleSprite(100 + i * 150, 100, 30, (255, 0, 0))
enemies.add(enemy)
all_sprites.add(enemy)
all_sprites.add(player)
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# Shoot bullet
bullet = Bullet(player.rect.centerx, player.rect.top)
bullets.add(bullet)
all_sprites.add(bullet)
# Update sprites
all_sprites.update()
# Collision detection with custom callback
hits = pygame.sprite.groupcollide(
bullets, enemies, True, True,
pygame.sprite.collide_circle
)
if hits:
print(f"Hit {len(hits)} enemies!")
# Draw everything
screen.fill((0, 0, 0))
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()import pygame
class MovingSprite(pygame.sprite.DirtySprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((50, 50))
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect(center=(x, y))
self.speed_x = 3
self.speed_y = 2
self.dirty = 1 # Mark as dirty initially
def update(self):
old_rect = self.rect.copy()
# Move sprite
self.rect.x += self.speed_x
self.rect.y += self.speed_y
# Bounce off edges
if self.rect.left < 0 or self.rect.right > 800:
self.speed_x = -self.speed_x
if self.rect.top < 0 or self.rect.bottom > 600:
self.speed_y = -self.speed_y
# Mark as dirty if moved
if self.rect != old_rect:
self.dirty = 1
# Create dirty group for optimized rendering
dirty_group = pygame.sprite.LayeredDirty()
# Add moving sprites
for i in range(10):
sprite = MovingSprite(i * 70 + 50, i * 50 + 50)
dirty_group.add(sprite)
pygame.init()
screen = pygame.display.set_mode((800, 600))
background = pygame.Surface((800, 600))
background.fill((0, 0, 100)) # Dark blue background
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Update sprites
dirty_group.update()
# Only redraw dirty areas
dirty_rects = dirty_group.draw(screen, background)
# Update only changed areas
pygame.display.update(dirty_rects)
clock.tick(60)
pygame.quit()Install with Tessl CLI
npx tessl i tessl/pypi-pygame-ce