Pure Python wrapper around SDL2 libraries for cross-platform multimedia development
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
High-level sprite management, animation, and rendering systems for 2D games and applications. The PySDL2 extension module provides object-oriented sprite classes and efficient batch rendering systems.
Core sprite classes for representing game objects and visual elements.
class Sprite:
"""
Base sprite class for 2D game objects.
Attributes:
- x: horizontal position
- y: vertical position
- size: (width, height) tuple
"""
def __init__(self, x: int = 0, y: int = 0):
"""
Create sprite at position.
Parameters:
- x: initial X coordinate
- y: initial Y coordinate
"""
@property
def position(self) -> tuple[int, int]:
"""Get sprite position as (x, y) tuple."""
@position.setter
def position(self, value: tuple[int, int]) -> None:
"""Set sprite position from (x, y) tuple."""
@property
def size(self) -> tuple[int, int]:
"""Get sprite size as (width, height) tuple."""
class SoftwareSprite(Sprite):
"""
Software-rendered sprite using SDL surfaces.
Uses CPU-based blitting for rendering. Best for applications with
few sprites or when hardware acceleration is unavailable.
"""
def __init__(self, surface: SDL_Surface, free: bool = False, x: int = 0, y: int = 0):
"""
Create software sprite from surface.
Parameters:
- surface: SDL_Surface containing sprite image
- free: whether to free surface when sprite is destroyed
- x, y: initial position
"""
class TextureSprite(Sprite):
"""
Hardware-accelerated sprite using SDL textures.
Uses GPU-based rendering for better performance. Requires
hardware-accelerated renderer.
"""
def __init__(self, texture: SDL_Texture, x: int = 0, y: int = 0):
"""
Create texture sprite from texture.
Parameters:
- texture: SDL_Texture containing sprite image
- x, y: initial position
"""Factory class for creating sprites from various sources.
class SpriteFactory:
"""Factory for creating sprites from images and other sources."""
def __init__(self, sprite_type: int = TEXTURE, renderer: Renderer = None,
fontmanager: FontManager = None):
"""
Create sprite factory.
Parameters:
- sprite_type: TEXTURE for TextureSprite, SOFTWARE for SoftwareSprite
- renderer: Renderer for texture sprites (required for TEXTURE type)
- fontmanager: FontManager for text sprites
"""
def from_image(self, fname: str) -> Sprite:
"""
Create sprite from image file.
Parameters:
- fname: path to image file
Returns:
Sprite object loaded from image
"""
def from_surface(self, surface: SDL_Surface, free: bool = False) -> Sprite:
"""
Create sprite from SDL surface.
Parameters:
- surface: SDL_Surface to create sprite from
- free: whether to free surface when sprite is destroyed
Returns:
Sprite object created from surface
"""
def from_color(self, color: tuple[int, int, int, int], size: tuple[int, int]) -> Sprite:
"""
Create solid color sprite.
Parameters:
- color: RGBA color tuple (0-255 each component)
- size: (width, height) sprite dimensions
Returns:
Sprite filled with solid color
"""
def from_text(self, text: str, font: FontTTF = None, size: int = 12,
color: tuple[int, int, int] = (255, 255, 255)) -> Sprite:
"""
Create text sprite.
Parameters:
- text: text string to render
- font: font to use (None for default)
- size: font size in points
- color: RGB text color
Returns:
Sprite containing rendered text
"""
def create_texture_sprite(self, renderer: Renderer, size: tuple[int, int]) -> TextureSprite:
"""
Create empty texture sprite for custom drawing.
Parameters:
- renderer: renderer to create texture for
- size: (width, height) texture dimensions
Returns:
Empty TextureSprite that can be drawn to
"""TEXTURE: int = 1 # Create TextureSprite objects
SOFTWARE: int = 2 # Create SoftwareSprite objectsEfficient batch rendering systems for sprites.
class SpriteRenderSystem:
"""Base class for sprite rendering systems."""
def render(self, sprites: list[Sprite]) -> None:
"""
Render list of sprites.
Parameters:
- sprites: list of Sprite objects to render
"""
class SoftwareSpriteRenderSystem(SpriteRenderSystem):
"""Software-based sprite rendering system using surface blitting."""
def __init__(self, window: Window):
"""
Create software sprite renderer.
Parameters:
- window: Window to render sprites to
"""
def render(self, sprites: list[Sprite]) -> None:
"""Render sprites using CPU blitting."""
class TextureSpriteRenderSystem(SpriteRenderSystem):
"""Hardware-accelerated sprite rendering system using textures."""
def __init__(self, renderer: Renderer):
"""
Create texture sprite renderer.
Parameters:
- renderer: Renderer to use for sprite rendering
"""
def render(self, sprites: list[Sprite]) -> None:
"""Render sprites using GPU acceleration."""
def render_sprite(self, sprite: TextureSprite, x: int = None, y: int = None,
area: SDL_Rect = None) -> None:
"""
Render single sprite.
Parameters:
- sprite: TextureSprite to render
- x, y: override position (None to use sprite position)
- area: source area to render (None for entire sprite)
"""Framework for managing game entities with component-based architecture.
class Entity:
"""
Game entity in entity-component system.
Entities are containers for components that define behavior
and properties.
"""
def __init__(self, world: World = None, *args, **kwargs):
"""
Create entity.
Parameters:
- world: World to add entity to
- args, kwargs: additional arguments
"""
class World:
"""
Container for entities and systems.
Manages entity lifecycle and system processing.
"""
def __init__(self):
"""Create empty world."""
def add_system(self, system: System) -> None:
"""
Add system to world.
Parameters:
- system: System to add
"""
def remove_system(self, system: System) -> None:
"""
Remove system from world.
Parameters:
- system: System to remove
"""
def get_entities(self, component: type) -> list[Entity]:
"""
Get entities that have specific component.
Parameters:
- component: component type to search for
Returns:
List of entities with the component
"""
def process(self) -> None:
"""Process all systems in the world."""
class System:
"""
Base class for entity-component systems.
Systems process entities that have specific components.
"""
def __init__(self):
"""Create system."""
def process(self, world: World, components: dict) -> None:
"""
Process entities with required components.
Parameters:
- world: World containing entities
- components: dictionary of component types to process
"""
class Applicator:
"""
Utility for applying functions to entities with specific components.
Provides functional programming interface for entity processing.
"""
def __init__(self, world: World):
"""
Create applicator for world.
Parameters:
- world: World to operate on
"""
def apply(self, func: callable, *component_types) -> None:
"""
Apply function to entities with specified components.
Parameters:
- func: function to apply to matching entities
- component_types: component types entities must have
"""Basic particle system for visual effects.
class ParticleEngine:
"""
Basic particle system for effects.
Note: This is from the particles module which may have encoding issues.
Check source if this doesn't work as expected.
"""
def __init__(self):
"""Create particle engine."""
def process(self, world: World, componentsets: dict) -> None:
"""Process particle components."""import sdl2.ext
# Initialize SDL2 extensions
sdl2.ext.init()
# Create window and renderer
window = sdl2.ext.Window("Sprite Example", size=(800, 600))
window.show()
renderer = sdl2.ext.Renderer(window)
# Create sprite factory for texture sprites
factory = sdl2.ext.SpriteFactory(sdl2.ext.TEXTURE, renderer=renderer)
# Create sprite from image file
player_sprite = factory.from_image("player.png")
player_sprite.position = (100, 100)
# Create colored sprite
enemy_sprite = factory.from_color((255, 0, 0, 255), (32, 32)) # Red 32x32 square
enemy_sprite.position = (200, 150)
# Create rendering system
render_system = sdl2.ext.TextureSpriteRenderSystem(renderer)
# Main game loop
running = True
while running:
# Handle events
events = sdl2.ext.get_events()
for event in events:
if event.type == sdl2.SDL_QUIT:
running = False
elif event.type == sdl2.SDL_KEYDOWN:
# Move player sprite with arrow keys
if event.key.keysym.sym == sdl2.SDLK_LEFT:
player_sprite.x -= 5
elif event.key.keysym.sym == sdl2.SDLK_RIGHT:
player_sprite.x += 5
elif event.key.keysym.sym == sdl2.SDLK_UP:
player_sprite.y -= 5
elif event.key.keysym.sym == sdl2.SDLK_DOWN:
player_sprite.y += 5
# Clear screen
renderer.clear((0, 50, 100))
# Render sprites
render_system.render([player_sprite, enemy_sprite])
# Present frame
renderer.present()
sdl2.ext.quit()import sdl2.ext
# Initialize with software rendering
sdl2.ext.init()
window = sdl2.ext.Window("Software Sprites", size=(640, 480))
window.show()
# Create software sprite factory
factory = sdl2.ext.SpriteFactory(sdl2.ext.SOFTWARE)
# Create sprites from images
sprites = []
for i in range(5):
sprite = factory.from_image(f"sprite_{i}.bmp")
sprite.position = (i * 100, 100)
sprites.append(sprite)
# Create software rendering system
render_system = sdl2.ext.SoftwareSpriteRenderSystem(window)
# Main loop
running = True
while running:
events = sdl2.ext.get_events()
for event in events:
if event.type == sdl2.SDL_QUIT:
running = False
# Move sprites
for sprite in sprites:
sprite.y = 100 + 50 * math.sin((sprite.x + frame_count) * 0.05)
# Render all sprites
render_system.render(sprites)
frame_count += 1
sdl2.ext.quit()import sdl2.ext
# Define components
class Position:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
class Velocity:
def __init__(self, vx=0, vy=0):
self.vx = vx
self.vy = vy
class Renderable:
def __init__(self, sprite):
self.sprite = sprite
# Define movement system
class MovementSystem(sdl2.ext.System):
def __init__(self):
super().__init__()
self.componenttypes = (Position, Velocity)
def process(self, world, componentsets):
for entity in componentsets:
position = entity[Position]
velocity = entity[Velocity]
position.x += velocity.vx
position.y += velocity.vy
# Wrap around screen edges
if position.x < 0:
position.x = 800
elif position.x > 800:
position.x = 0
# Initialize SDL2
sdl2.ext.init()
window = sdl2.ext.Window("ECS Example", size=(800, 600))
window.show()
renderer = sdl2.ext.Renderer(window)
# Create world and systems
world = sdl2.ext.World()
movement_system = MovementSystem()
render_system = sdl2.ext.TextureSpriteRenderSystem(renderer)
world.add_system(movement_system)
# Create sprite factory
factory = sdl2.ext.SpriteFactory(sdl2.ext.TEXTURE, renderer=renderer)
# Create entities
for i in range(10):
entity = sdl2.ext.Entity(world)
# Add components
entity.components[Position] = Position(i * 80, 200)
entity.components[Velocity] = Velocity(random.randint(-3, 3), random.randint(-2, 2))
sprite = factory.from_color((255, 255, 0, 255), (16, 16))
entity.components[Renderable] = Renderable(sprite)
# Main loop
running = True
while running:
events = sdl2.ext.get_events()
for event in events:
if event.type == sdl2.SDL_QUIT:
running = False
# Process systems
world.process()
# Render
renderer.clear((0, 0, 0))
# Get all entities with Position and Renderable components
renderable_entities = world.get_entities((Position, Renderable))
sprites_to_render = []
for entity in renderable_entities:
position = entity.components[Position]
renderable = entity.components[Renderable]
renderable.sprite.position = (position.x, position.y)
sprites_to_render.append(renderable.sprite)
render_system.render(sprites_to_render)
renderer.present()
sdl2.ext.quit()import sdl2.ext
import time
# Initialize SDL2
sdl2.ext.init()
window = sdl2.ext.Window("Sprite Animation", size=(800, 600))
window.show()
renderer = sdl2.ext.Renderer(window)
# Create sprite factory
factory = sdl2.ext.SpriteFactory(sdl2.ext.TEXTURE, renderer=renderer)
# Load animation frames
animation_frames = []
for i in range(8): # Assuming 8 frame animation
frame = factory.from_image(f"animation_frame_{i}.png")
animation_frames.append(frame)
# Animation variables
current_frame = 0
frame_duration = 0.1 # 100ms per frame
last_frame_time = time.time()
# Create rendering system
render_system = sdl2.ext.TextureSpriteRenderSystem(renderer)
# Main loop
running = True
while running:
current_time = time.time()
events = sdl2.ext.get_events()
for event in events:
if event.type == sdl2.SDL_QUIT:
running = False
# Update animation
if current_time - last_frame_time >= frame_duration:
current_frame = (current_frame + 1) % len(animation_frames)
last_frame_time = current_time
# Position current frame
current_sprite = animation_frames[current_frame]
current_sprite.position = (350, 250)
# Render
renderer.clear((0, 0, 0))
render_system.render([current_sprite])
renderer.present()
sdl2.ext.quit()Install with Tessl CLI
npx tessl i tessl/pypi-pysdl2