Skip to main content

Overview

The SimpleAnimation class provides a simple way to create sprite animations by cycling through a list of images. It handles timing, rendering, and optional duration limits automatically.
SimpleAnimation uses the Timer class internally to manage frame scrolling and duration.

Creating an Animation

import pygame
from simpleanimation import SimpleAnimation

# Load animation frames
frames = [
    pygame.image.load('explosion_frame1.png').convert_alpha(),
    pygame.image.load('explosion_frame2.png').convert_alpha(),
    pygame.image.load('explosion_frame3.png').convert_alpha()
]

# Create animation that cycles every 100ms, lasting 2 seconds
explosion = SimpleAnimation(
    screen=game_screen,
    pos=(200, 150),
    images=frames,
    scroll_period=100,
    duration=2000
)

Constructor Parameters

screen
pygame.Surface
required
The pygame surface to draw the animation on.
pos
tuple
Position (x, y) on the screen where the animation will be drawn.
images
list[pygame.Surface]
required
List of pygame Surface objects to cycle through. These are your animation frames.
scroll_period
int
required
Time in milliseconds between frame changes. Smaller values = faster animation.Examples:
  • 100 = 10 frames per second
  • 50 = 20 frames per second
  • 33 = ~30 frames per second
duration
int
default:"-1"
Total duration of the animation in milliseconds. Set to -1 for infinite duration.When duration expires, the animation becomes inactive.

Update and Draw

Animations require two method calls each frame:
# In your game loop
while running:
    time_passed = clock.tick(60)
    
    # Update animation state
    animation.update(time_passed)
    
    # Draw the current frame
    animation.draw()
    
    pygame.display.flip()

update(time_passed)

time_passed
int
required
Milliseconds elapsed since the last update. Typically obtained from pygame.time.Clock.tick().
Updates the internal timers:
  • Scroll timer: Advances to the next frame when the scroll period elapses
  • Active timer: Deactivates the animation when the duration expires

draw()

Renders the current animation frame to the screen at the specified position.
draw() only renders if the animation is active. Once duration expires, drawing stops automatically.

Animation Lifecycle

Active State

Check if an animation is still running:
if animation.is_active():
    print("Animation is playing")
else:
    print("Animation has finished")
Animations with duration=-1 run forever.
# Runs indefinitely
idle_animation = SimpleAnimation(
    screen=screen,
    pos=(100, 100),
    images=idle_frames,
    scroll_period=150,
    duration=-1  # Never stops
)
Use Cases:
  • Character idle animations
  • Background elements (water, fire)
  • UI loading indicators
  • Ambient effects

Scroll Period vs Duration

Understanding the difference between these two timing parameters:

Scroll Period

Controls: How fast frames changeUnits: Milliseconds per frameExample: scroll_period=100 means each frame shows for 100ms

Duration

Controls: How long the entire animation runsUnits: Total millisecondsExample: duration=2000 means animation stops after 2 seconds
# Animation with 4 frames, 100ms per frame, 2 second total
animation = SimpleAnimation(
    screen=screen,
    pos=(100, 100),
    images=[frame1, frame2, frame3, frame4],
    scroll_period=100,  # Each frame shows for 100ms
    duration=2000       # Animation runs for 2000ms total
)

# This animation will cycle through all 4 frames 5 times:
# 4 frames × 100ms = 400ms per cycle
# 2000ms / 400ms = 5 complete cycles

Real Usage Example

From simpleanimation.py:77:
simpleanimation.py:67
if __name__ == "__main__":
    print "initializing"
    pygame.init()
    screen = pygame.display.set_mode((300, 300), 0, 32)

    clock = pygame.time.Clock()
    
    # Load explosion image and create rotated variant
    explosion_img = pygame.image.load('images/explosion1.png').convert_alpha()
    images = [explosion_img, pygame.transform.rotate(explosion_img, 90)]

    # Create explosion animation that lasts just over 2 seconds
    expl = SimpleAnimation(screen, (100, 100), images, 100, 2120)

    while True:
        time_passed = clock.tick(50)
        
        screen.fill((0, 0, 0))
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
        
        # Update and draw the animation
        expl.update(time_passed)
        expl.draw()
        
        pygame.display.flip()
This creates a simple 2-frame animation that rotates between an explosion image and its 90° rotation.

Managing Multiple Animations

class AnimationManager:
    def __init__(self, screen):
        self.screen = screen
        self.animations = []
    
    def add_animation(self, pos, images, scroll_period, duration=-1):
        anim = SimpleAnimation(
            self.screen, pos, images, scroll_period, duration
        )
        self.animations.append(anim)
        return anim
    
    def update(self, time_passed):
        # Update all animations
        for anim in self.animations:
            anim.update(time_passed)
        
        # Remove finished animations
        self.animations = [
            a for a in self.animations if a.is_active()
        ]
    
    def draw(self):
        for anim in self.animations:
            anim.draw()

# Usage
anim_mgr = AnimationManager(screen)

# Add explosions at different locations
anim_mgr.add_animation((100, 100), explosion_frames, 50, 1000)
anim_mgr.add_animation((200, 150), explosion_frames, 50, 1000)

# In game loop
while running:
    time_passed = clock.tick(60)
    anim_mgr.update(time_passed)
    anim_mgr.draw()

Common Patterns

Explosion Effect

def create_explosion(screen, pos):
    frames = [
        pygame.image.load(f'explosion{i}.png').convert_alpha()
        for i in range(1, 6)
    ]
    return SimpleAnimation(
        screen=screen,
        pos=pos,
        images=frames,
        scroll_period=50,   # Fast animation
        duration=250        # Brief effect
    )

# Trigger explosion
explosion = create_explosion(screen, enemy.pos)

Character Idle Animation

class Character:
    def __init__(self, screen, pos):
        idle_frames = self.load_idle_frames()
        self.idle_anim = SimpleAnimation(
            screen=screen,
            pos=pos,
            images=idle_frames,
            scroll_period=200,  # Slow, breathing animation
            duration=-1          # Loop forever
        )
    
    def update(self, time_passed):
        self.idle_anim.update(time_passed)
    
    def draw(self):
        self.idle_anim.draw()

Loading Indicator

class LoadingSpinner:
    def __init__(self, screen, center_pos):
        # Create rotating frames
        base = pygame.image.load('spinner.png').convert_alpha()
        frames = [
            pygame.transform.rotate(base, angle)
            for angle in range(0, 360, 45)
        ]
        
        self.animation = SimpleAnimation(
            screen=screen,
            pos=center_pos,
            images=frames,
            scroll_period=100,  # Smooth rotation
            duration=-1          # Infinite
        )

Performance Considerations

Optimize image loading: Load animation frames once and reuse them across multiple animation instances.
# Good: Load frames once
class AnimationFrames:
    explosion = None
    
    @classmethod
    def load(cls):
        if cls.explosion is None:
            cls.explosion = [
                pygame.image.load(f'explosion{i}.png').convert_alpha()
                for i in range(1, 6)
            ]

# Reuse for multiple explosions
AnimationFrames.load()

explosion1 = SimpleAnimation(screen, pos1, AnimationFrames.explosion, 50, 500)
explosion2 = SimpleAnimation(screen, pos2, AnimationFrames.explosion, 50, 500)

Internal Implementation

SimpleAnimation uses two internal timers:
simpleanimation.py:32
self.scroll_timer = Timer(scroll_period, self._advance_img)
self.active_timer = Timer(duration, self._inactivate, True)
  • scroll_timer: Repeating timer that calls _advance_img() to cycle frames
  • active_timer: One-shot timer that calls _inactivate() when duration expires

API Reference

Constructor

SimpleAnimation(screen, pos, images, scroll_period, duration=-1)

Methods

update(time_passed)
None
Updates the animation state by advancing the internal timers.Parameters:
  • time_passed (int): Milliseconds since last update
draw()
None
Renders the current frame to the screen if the animation is active.
is_active()
bool
Returns True if the animation is still running, False if it has finished.

Attributes

screen
pygame.Surface
The target surface for drawing
pos
tuple
Current position (x, y) of the animation
images
list[pygame.Surface]
List of animation frames
img_ptr
int
Index of the currently displayed frame
active
bool
Whether the animation is currently active
scroll_timer
Timer
Internal timer for frame advancement
active_timer
Timer
Internal timer for duration tracking

Build docs developers (and LLMs) love