spritesheet.py

Sprite Sheet System with Alpha Support and Time-Based Animations

LOCATION: lunaengine/graphics/spritesheet.py

DESCRIPTION:
Advanced sprite sheet management system with alpha channel support and
time-based animation system. Provides efficient sprite extraction from
texture atlases with flexible positioning and frame-rate independent animations.

KEY FEATURES:
- Full alpha channel support for transparent sprites
- Flexible sprite extraction using Rect coordinates
- Batch sprite extraction for multiple regions
- Time-based animation system (frame-rate independent)
- Support for padding, margin, and scaling
- Animation sequencing with configurable durations
- Automatic frame extraction based on parameters

LIBRARIES USED:
- pygame: Image loading, surface manipulation, and alpha processing
- typing: Type hints for better code documentation
- time: Animation timing calculations

! WARN:
- Ensure pygame is initialized before using this module

USAGE:
>>> # Basic sprite sheet
>>> spritesheet = SpriteSheet("characters.png")
>>> single_sprite = spritesheet.get_sprite_at_rect(pygame.Rect(0, 0, 64, 64))
>>>
>>> # Multiple sprites
>>> regions = [pygame.Rect(0, 0, 64, 64), pygame.Rect(64, 0, 64, 64)]
>>> sprites = spritesheet.get_sprites_at_regions(regions)
>>>
>>> # Animation - automatically extracts frames
>>> walk_animation = Animation("tiki_texture.png", (70, 70), (0, 0), frame_count=6,
>>>                           scale=(2, 2), duration=1.0)
>>> current_frame = walk_animation.get_current_frame()

class SpriteSheet

Description

Main sprite sheet class for managing and extracting sprites from texture atlases.

This class handles loading sprite sheets with alpha support and provides
multiple methods for extracting individual sprites or sprite sequences.

Attributes:
   sheet (pygame.Surface): The loaded sprite sheet surface with alpha
   filename (str): Path to the sprite sheet file
   width (int): Width of the sprite sheet
   height (int): Height of the sprite sheet

Methods
def __init__(self: Any, filename: str) -> Any
Initialize the sprite sheet with alpha support.

Args:
   filename (str): Path to the sprite sheet image file
def get_sprite_at_rect(self: Any, rect: pygame.Rect) -> pygame.Surface
Extract a sprite from a specific rectangular region.

Args:
   rect (pygame.Rect): Rectangle defining the sprite region (x, y, width, height)

Returns:
   pygame.Surface: The extracted sprite surface with alpha

Raises:
   ValueError: If the rect is outside the sprite sheet bounds
def get_sprites_at_regions(self: Any, regions: List[pygame.Rect]) -> List[pygame.Surface]
Extract multiple sprites from a list of rectangular regions.

Args:
   regions (List[pygame.Rect]): List of rectangles defining sprite regions

Returns:
   List[pygame.Surface]: List of extracted sprite surfaces
def get_sprite_grid(self: Any, cell_size: Tuple[int, int], grid_pos: Tuple[int, int]) -> pygame.Surface
Extract a sprite from a grid-based sprite sheet.

Args:
   cell_size (Tuple[int, int]): Width and height of each grid cell
   grid_pos (Tuple[int, int]): Grid coordinates (col, row)

Returns:
   pygame.Surface: The extracted sprite surface
def get_surface_drawn_area(self: Any, surface: pygame.Surface, threshold: int = 1) -> pygame.Rect
Get the bounding rectangle of the non-transparent (drawn) area of a surface.

This function analyzes the alpha channel of the surface to find the smallest
rectangle that contains all non-transparent pixels, creating a tight hitbox.

Args:
   surface (pygame.Surface): Surface to analyze (must have alpha channel)
   threshold (int): Alpha threshold value (0-255). Pixels with alpha >= threshold
                   are considered drawn. Default is 1 (any non-fully-transparent).

Returns:
   pygame.Rect: Tight bounding rectangle around the non-transparent area.
               Returns empty Rect (0,0,0,0) if surface is fully transparent.

Raises:
   ValueError: If surface doesn't have per-pixel alpha

class Animation

Description

Time-based animation system for sprite sequences with fade effects.

This class automatically extracts frames from a sprite sheet based on
the provided parameters and manages animation timing with alpha transitions.

Attributes:
   spritesheet (SpriteSheet): The source sprite sheet
   frames (List[pygame.Surface]): List of animation frames
   frame_count (int): Total number of frames in the animation
   current_frame_index (int): Current frame index in the animation
   duration (float): Total animation duration in seconds
   frame_duration (float): Duration of each frame in seconds
   last_update_time (float): Last time the animation was updated
   scale (Tuple[float, float]): Scale factors for the animation
   loop (bool): Whether the animation should loop
   playing (bool): Whether the animation is currently playing
   fade_in_duration (float): Duration of fade-in effect in seconds
   fade_out_duration (float): Duration of fade-out effect in seconds
   fade_alpha (int): Current alpha value for fade effects (0-255)
   fade_mode (str): Current fade mode: 'in', 'out', or None
   flip (Tuple[bool, bool]): Flip flags for horizontal and vertical flipping

Methods
def __init__(self: Any, spritesheet_file: str, size: Tuple[int, int], start_pos: Tuple[int, int] = (0, 0), frame_count: int = 1, padding: Tuple[int, int] = (0, 0), margin: Tuple[int, int] = (0, 0), scale: Tuple[float, float] = (1.0, 1.0), duration: float = 1.0, loop: bool = True, fade_in_duration: float = 0.0, fade_out_duration: float = 0.0, flip: tuple = (False, False)) -> Any
Initialize the animation and automatically extract frames from sprite sheet.

Args:
   spritesheet_file (str): Path to the sprite sheet file
   size (Tuple[int, int]): Size of each sprite (width, height)
   start_pos (Tuple[int, int]): Starting position in the sprite sheet (x, y)
   frame_count (int): Number of frames to extract for the animation
   padding (Tuple[int, int]): Padding between sprites (x, y)
   margin (Tuple[int, int]): Margin around the sprite sheet (x, y)
   scale (Tuple[float, float]): Scale factors for the animation
   duration (float): Total animation duration in seconds
   loop (bool): Whether the animation should loop
   fade_in_duration (float): Duration of fade-in effect in seconds
   fade_out_duration (float): Duration of fade-out effect in seconds
   flip (Tuple[bool, bool]): Flip the animation horizontally and vertically
def _extract_animation_frames(self: Any) -> List[pygame.Surface]
Automatically extract animation frames based on parameters.

Creates a sequence of rectangles and extracts the corresponding sprites
from the sprite sheet.

Returns:
   List[pygame.Surface]: List of extracted frames
def _apply_scaling(self: Any) -> Any
Apply scaling to all animation frames.
def set_duration(self: Any, new_duration: float) -> Any
Change the animation duration.

Args:
   new_duration (float): New total duration in seconds
def play(self: Any) -> Any
Start or resume the animation.
def pause(self: Any) -> Any
Pause the animation.
def get_frame_count(self: Any) -> int
Get the number of frames in the animation.

Returns:
   int: Number of frames
def get_progress(self: Any) -> float
Get the current progress of the animation (0.0 to 1.0).

Returns:
   float: Animation progress from start (0.0) to end (1.0)
def _apply_fade_effect(self: Any, surface: pygame.Surface) -> pygame.Surface
Apply current fade alpha to a surface.

Args:
   surface (pygame.Surface): Original surface

Returns:
   pygame.Surface: Surface with fade effect applied
def update_fade(self: Any) -> Any
Update fade-in and fade-out effects based on elapsed time.
def update(self: Any) -> Any
Update the animation based on elapsed time including fade effects.

This method uses time-based animation rather than frame-based,
making it frame-rate independent.
def get_current_frame(self: Any) -> pygame.Surface
Get the current animation frame with fade effects applied.

Returns:
   pygame.Surface: The current frame surface with fade alpha
def start_fade_in(self: Any, duration: Optional[float] = None) -> Any
Start a fade-in effect.

Args:
   duration (float, optional): Override fade-in duration. If None, uses initialized value.
def start_fade_out(self: Any, duration: Optional[float] = None) -> Any
Start a fade-out effect.

Args:
   duration (float, optional): Override fade-out duration. If None, uses initialized value.
def set_fade_alpha(self: Any, alpha: int) -> Any
Manually set the fade alpha value.

Args:
   alpha (int): Alpha value from 0 (transparent) to 255 (opaque)
def is_fade_complete(self: Any) -> bool
Check if the current fade effect is complete.

Returns:
   bool: True if no fade effect is active or fade is complete
def reset(self: Any) -> Any
Reset the animation to the first frame and reset fade effects.
Back to Graphics Module