Advanced particle system for creating fireworks, explosions, rain, and other dynamic effects, combined with sprite animation support for character-based animations and custom drawable objects. The particle system provides realistic physics simulation while sprites enable complex animated sequences.
The foundation classes for creating particle-based effects with physics simulation and lifecycle management.
class Particle:
"""Individual particle with physics properties"""
def __init__(self, x, y, dx, dy, char, colour, life_time, bg=0):
"""
Initialize particle with position, velocity, and appearance.
Parameters:
- x (float): Initial X position
- y (float): Initial Y position
- dx (float): X velocity
- dy (float): Y velocity
- char (str): Character to display for particle
- colour (int): Particle color
- life_time (int): Frames particle will live
- bg (int): Background color
"""
def update(self):
"""Update particle position and physics"""
@property
def is_alive(self):
"""Whether particle is still alive"""
class ParticleEmitter:
"""Base class for particle emission sources"""
def __init__(self, screen, x, y, max_particles=100):
"""
Initialize particle emitter.
Parameters:
- screen (Screen): Target screen for rendering
- x (int): Emitter X position
- y (int): Emitter Y position
- max_particles (int): Maximum particles to emit
"""
def update(self, frame_no):
"""
Update emitter and emit new particles.
Parameters:
- frame_no (int): Current animation frame
Returns:
list: List of new particles created this frame
"""
class ParticleEffect(Effect):
"""Base class for particle-based effects"""
def __init__(self, screen, x, y, life_time, start_frame=0, stop_frame=0):
"""
Initialize particle effect.
Parameters:
- screen (Screen): Target screen
- x (int): Effect center X position
- y (int): Effect center Y position
- life_time (int): Effect duration in frames
- start_frame (int): Frame to start effect
- stop_frame (int): Frame to stop effect
"""Specialized emitters for different types of particle behaviors and visual effects.
class Rocket(ParticleEmitter):
"""Rocket trail particle emitter"""
def __init__(self, screen, x, y, dx, dy, life_time, colour):
"""
Initialize rocket emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Starting X position
- y (int): Starting Y position
- dx (float): X direction/velocity
- dy (float): Y direction/velocity
- life_time (int): Rocket trail duration
- colour (int): Rocket color
"""
class RingExplosion(ParticleEmitter):
"""Ring explosion particle emitter"""
def __init__(self, screen, x, y, life_time, colour):
"""
Initialize ring explosion emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Explosion center X
- y (int): Explosion center Y
- life_time (int): Explosion duration
- colour (int): Explosion color
"""
class SerpentExplosion(ParticleEmitter):
"""Serpent-style explosion particle emitter"""
def __init__(self, screen, x, y, life_time, colour):
"""
Initialize serpent explosion emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Explosion center X
- y (int): Explosion center Y
- life_time (int): Explosion duration
- colour (int): Explosion color
"""
class StarExplosion(ParticleEmitter):
"""Star-shaped explosion particle emitter"""
def __init__(self, screen, x, y, life_time, colour):
"""
Initialize star explosion emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Explosion center X
- y (int): Explosion center Y
- life_time (int): Explosion duration
- colour (int): Explosion color
"""
class StarTrail(ParticleEmitter):
"""Star trail particle emitter"""
def __init__(self, screen, x, y, life_time, colour):
"""
Initialize star trail emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Trail start X
- y (int): Trail start Y
- life_time (int): Trail duration
- colour (int): Trail color
"""
class PalmExplosion(ParticleEmitter):
"""Palm tree explosion particle emitter"""
def __init__(self, screen, x, y, life_time, colour):
"""
Initialize palm explosion emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Explosion center X
- y (int): Explosion center Y
- life_time (int): Explosion duration
- colour (int): Explosion color
"""
class ExplosionFlames(ParticleEmitter):
"""Explosion flames particle emitter"""
def __init__(self, screen, x, y, life_time, colour):
"""
Initialize explosion flames emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Flames center X
- y (int): Flames center Y
- life_time (int): Flames duration
- colour (int): Flames color
"""Emitters for environmental effects like rain, drops, and weather.
class DropEmitter(ParticleEmitter):
"""Water drop particle emitter"""
def __init__(self, screen, x, y, rate, colour):
"""
Initialize drop emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Drop source X
- y (int): Drop source Y
- rate (float): Drop emission rate
- colour (int): Drop color
"""
class ShotEmitter(ParticleEmitter):
"""Shot/bullet particle emitter"""
def __init__(self, screen, x, y, dx, dy, colour, life_time):
"""
Initialize shot emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Shot origin X
- y (int): Shot origin Y
- dx (float): Shot X velocity
- dy (float): Shot Y velocity
- colour (int): Shot color
- life_time (int): Shot duration
"""
class RainSource(ParticleEmitter):
"""Rain source particle emitter"""
def __init__(self, screen, width, intensity, colour):
"""
Initialize rain source emitter.
Parameters:
- screen (Screen): Target screen
- width (int): Rain area width
- intensity (float): Rain intensity/rate
- colour (int): Rain color
"""
class Splash(ParticleEmitter):
"""Water splash particle emitter"""
def __init__(self, screen, x, y, life_time, colour):
"""
Initialize splash emitter.
Parameters:
- screen (Screen): Target screen
- x (int): Splash center X
- y (int): Splash center Y
- life_time (int): Splash duration
- colour (int): Splash color
"""Complete firework effects combining multiple emitters for realistic pyrotechnic displays.
class StarFirework(ParticleEffect):
"""Star-shaped firework effect"""
def __init__(self, screen, x, y, life_time, firework_colour=7, trail_colour=None, start_frame=0):
"""
Initialize star firework effect.
Parameters:
- screen (Screen): Target screen
- x (int): Firework X position
- y (int): Firework Y position
- life_time (int): Firework duration
- firework_colour (int): Main firework color
- trail_colour (int): Trail color (None = same as firework)
- start_frame (int): Frame to start firework
"""
class RingFirework(ParticleEffect):
"""Ring-shaped firework effect"""
def __init__(self, screen, x, y, life_time, firework_colour=7, trail_colour=None, start_frame=0):
"""
Initialize ring firework effect.
Parameters:
- screen (Screen): Target screen
- x (int): Firework X position
- y (int): Firework Y position
- life_time (int): Firework duration
- firework_colour (int): Main firework color
- trail_colour (int): Trail color (None = same as firework)
- start_frame (int): Frame to start firework
"""
class SerpentFirework(ParticleEffect):
"""Serpent-style firework effect"""
def __init__(self, screen, x, y, life_time, firework_colour=7, trail_colour=None, start_frame=0):
"""
Initialize serpent firework effect.
Parameters:
- screen (Screen): Target screen
- x (int): Firework X position
- y (int): Firework Y position
- life_time (int): Firework duration
- firework_colour (int): Main firework color
- trail_colour (int): Trail color (None = same as firework)
- start_frame (int): Frame to start firework
"""
class PalmFirework(ParticleEffect):
"""Palm tree firework effect"""
def __init__(self, screen, x, y, life_time, firework_colour=7, trail_colour=None, start_frame=0):
"""
Initialize palm firework effect.
Parameters:
- screen (Screen): Target screen
- x (int): Firework X position
- y (int): Firework Y position
- life_time (int): Firework duration
- firework_colour (int): Main firework color
- trail_colour (int): Trail color (None = same as firework)
- start_frame (int): Frame to start firework
"""
class Explosion(ParticleEffect):
"""Generic explosion effect"""
def __init__(self, screen, x, y, life_time, start_frame=0):
"""
Initialize explosion effect.
Parameters:
- screen (Screen): Target screen
- x (int): Explosion center X
- y (int): Explosion center Y
- life_time (int): Explosion duration
- start_frame (int): Frame to start explosion
"""Large-scale environmental effects using particle systems.
class DropScreen(ParticleEffect):
"""Full-screen drop effect"""
def __init__(self, screen, life_time, start_frame=0):
"""
Initialize drop screen effect.
Parameters:
- screen (Screen): Target screen
- life_time (int): Effect duration
- start_frame (int): Frame to start effect
"""
class ShootScreen(ParticleEffect):
"""Full-screen shooting effect"""
def __init__(self, screen, life_time, start_frame=0):
"""
Initialize shoot screen effect.
Parameters:
- screen (Screen): Target screen
- life_time (int): Effect duration
- start_frame (int): Frame to start effect
"""
class Rain(ParticleEffect):
"""Rain weather effect"""
def __init__(self, screen, life_time, start_frame=0):
"""
Initialize rain effect.
Parameters:
- screen (Screen): Target screen
- life_time (int): Rain duration
- start_frame (int): Frame to start rain
"""Character-based animation system for complex moving objects and sequences.
class Sprite(Effect):
"""Moving sprite animation effect"""
def __init__(self, screen, renderer_dict, path, colour=7, attr=2, bg=0, clear=True, start_frame=0, stop_frame=0):
"""
Initialize sprite animation.
Parameters:
- screen (Screen): Target screen
- renderer_dict (dict): Dictionary mapping animation states to renderers
- path (Path): Animation path for sprite movement
- colour (int): Sprite color
- attr (int): Text attributes
- bg (int): Background color
- clear (bool): Whether to clear sprite trail
- start_frame (int): Frame to start animation
- stop_frame (int): Frame to stop animation
"""
def overlaps(self, other_sprite, use_new_pos=False):
"""
Check if sprite overlaps with another sprite.
Parameters:
- other_sprite (Sprite): Other sprite to check collision with
- use_new_pos (bool): Whether to use new position for check
Returns:
bool: True if sprites overlap
"""
@property
def x(self):
"""Current sprite X position"""
@property
def y(self):
"""Current sprite Y position"""
class Sam(Sprite):
"""Sam character sprite with built-in animations"""
def __init__(self, screen, path, start_frame=0, stop_frame=0):
"""
Initialize Sam sprite.
Parameters:
- screen (Screen): Target screen
- path (Path): Movement path for Sam
- start_frame (int): Frame to start animation
- stop_frame (int): Frame to stop animation
"""
class Arrow(Sprite):
"""Arrow sprite for projectiles and indicators"""
def __init__(self, screen, path, colour=7, start_frame=0, stop_frame=0):
"""
Initialize arrow sprite.
Parameters:
- screen (Screen): Target screen
- path (Path): Movement path for arrow
- colour (int): Arrow color
- start_frame (int): Frame to start animation
- stop_frame (int): Frame to stop animation
"""
class Plot(Sprite):
"""Plot/graph sprite for data visualization"""
def __init__(self, screen, path, colour=7, start_frame=0, stop_frame=0):
"""
Initialize plot sprite.
Parameters:
- screen (Screen): Target screen
- path (Path): Movement path for plot
- colour (int): Plot color
- start_frame (int): Frame to start animation
- stop_frame (int): Frame to stop animation
"""
class Arrow(Sprite):
"""Arrow sprite for projectiles and indicators"""
def __init__(self, screen, path, colour=7, start_frame=0, stop_frame=0):
"""
Initialize arrow sprite.
Parameters:
- screen (Screen): Target screen
- path (Path): Movement path for arrow
- colour (int): Arrow color
- start_frame (int): Frame to start animation
- stop_frame (int): Frame to stop animation
"""Path system for controlling sprite movement and animation trajectories.
class Path:
"""Static animation path for sprite movement"""
def __init__(self, screen, x, y, path):
"""
Initialize static path.
Parameters:
- screen (Screen): Target screen
- x (int): Starting X position
- y (int): Starting Y position
- path (str): Path string defining movement
"""
def next_pos(self):
"""
Get next position on path.
Returns:
tuple: (x, y, finished) position and completion status
"""
class DynamicPath:
"""Abstract base class for dynamic animation paths"""
def __init__(self, screen, x, y):
"""
Initialize dynamic path.
Parameters:
- screen (Screen): Target screen
- x (int): Starting X position
- y (int): Starting Y position
"""
def process_event(self, event):
"""
Process input event for path modification.
Parameters:
- event (Event): Input event to process
"""
def next_pos(self):
"""
Get next position on dynamic path.
Returns:
tuple: (x, y, finished) position and completion status
"""from asciimatics.screen import ManagedScreen
from asciimatics.scene import Scene
from asciimatics.particles import StarFirework, RingFirework, PalmFirework
from asciimatics.effects import Stars
import random
def fireworks_demo(screen):
effects = [
Stars(screen, 200), # Background stars
]
# Add random fireworks
for i in range(10):
x = random.randint(10, screen.width - 10)
y = random.randint(5, screen.height // 2)
start_time = random.randint(0, 300)
firework_type = random.choice([StarFirework, RingFirework, PalmFirework])
color = random.randint(1, 7)
effects.append(
firework_type(screen, x, y, 100,
firework_colour=color,
start_frame=start_time)
)
screen.play([Scene(effects, 500)])
ManagedScreen(fireworks_demo).run()from asciimatics.particles import Rain
from asciimatics.effects import Print
from asciimatics.renderers import FigletText
def rain_demo(screen):
effects = [
Rain(screen, -1), # Infinite rain
Print(screen,
FigletText("RAINY DAY", font='small'),
screen.height // 2,
colour=Screen.COLOUR_BLUE)
]
screen.play([Scene(effects, -1)])
ManagedScreen(rain_demo).run()from asciimatics.sprites import Sam
from asciimatics.paths import Path
from asciimatics.effects import Stars
def sprite_demo(screen):
# Create path for Sam to follow
path_string = f"M{screen.width//4},{screen.height//2} L{screen.width*3//4},{screen.height//2}"
path = Path(screen, screen.width//4, screen.height//2, path_string)
effects = [
Stars(screen, 100), # Background
Sam(screen, path) # Sam sprite following path
]
screen.play([Scene(effects, 500)])
ManagedScreen(sprite_demo).run()from asciimatics.particles import ParticleEffect, ParticleEmitter, Particle
import random
class SnowFlakeEmitter(ParticleEmitter):
"""Custom snowflake particle emitter"""
def update(self, frame_no):
particles = []
# Emit snowflakes from top of screen
if frame_no % 3 == 0: # Every 3 frames
x = random.randint(0, self._screen.width - 1)
particle = Particle(
x=x, y=0,
dx=random.uniform(-0.5, 0.5), # Slight horizontal drift
dy=random.uniform(0.2, 0.8), # Downward movement
char="*",
colour=Screen.COLOUR_WHITE,
life_time=self._screen.height * 2 # Live long enough to cross screen
)
particles.append(particle)
return particles
class CustomSnow(ParticleEffect):
"""Custom snow effect using snowflake emitter"""
def __init__(self, screen, life_time, start_frame=0):
super().__init__(screen, 0, 0, life_time, start_frame)
self._emitter = SnowFlakeEmitter(screen, 0, 0)
self._particles = []
def update(self, frame_no):
# Add new particles
new_particles = self._emitter.update(frame_no)
self._particles.extend(new_particles)
# Update existing particles
active_particles = []
for particle in self._particles:
particle.update()
if particle.is_alive and 0 <= particle.y < self._screen.height:
active_particles.append(particle)
self._screen.print_at(
particle.char,
int(particle.x),
int(particle.y),
particle.colour
)
self._particles = active_particles
return True
def custom_snow_demo(screen):
effects = [
CustomSnow(screen, -1) # Infinite snow
]
screen.play([Scene(effects, -1)])
ManagedScreen(custom_snow_demo).run()from asciimatics.sprites import Sam, Arrow
from asciimatics.paths import Path
def collision_demo(screen):
# Create paths
sam_path = Path(screen, 10, screen.height//2,
f"L{screen.width-20},{screen.height//2}")
arrow_path = Path(screen, screen.width-10, screen.height//2-5,
f"L10,{screen.height//2-5}")
# Create sprites
sam = Sam(screen, sam_path)
arrow = Arrow(screen, arrow_path, colour=Screen.COLOUR_RED)
class CollisionChecker(Effect):
def __init__(self, sprite1, sprite2):
super().__init__(screen)
self._sprite1 = sprite1
self._sprite2 = sprite2
def update(self, frame_no):
if self._sprite1.overlaps(self._sprite2):
self._screen.print_at("COLLISION!",
screen.width//2-5,
screen.height//2+5,
Screen.COLOUR_YELLOW,
Screen.A_BOLD)
return True
effects = [
sam,
arrow,
CollisionChecker(sam, arrow)
]
screen.play([Scene(effects, 400)])
ManagedScreen(collision_demo).run()