Skip to content

Instantly share code, notes, and snippets.

@todbot
Last active May 15, 2024 00:05
Show Gist options
  • Save todbot/f5a013918c208451424cea9d701f99c5 to your computer and use it in GitHub Desktop.
Save todbot/f5a013918c208451424cea9d701f99c5 to your computer and use it in GitHub Desktop.
Fireworks display using sprites in CircuitPython
# fireworks_sprites.py - show a bunch of fireworks
# 4 Jul 2022 - @todbot / Tod Kurt
import time, random
import board
import displayio
import rainbowio
import adafruit_imageload
fireworks_count = 5
sprite_fname = "fireworks_spritesheet.bmp"
sprite_count = 30*1
sprite_w,sprite_h = 64,64
display = board.DISPLAY # our board has built-in display
dw,dh = display.width, display.height # convenience values
sprite_sheet, sprite_palette = adafruit_imageload.load(sprite_fname)
maingroup = displayio.Group() # all fireworks go on 'maingroup'
display.show(maingroup)
def random_xy():
return random.randint(0, dw-sprite_w), random.randint(dh//2, dh//2+20)
def copy_palette(p): # this is fastest way to copy a palette it seems
new_p = displayio.Palette(len(p))
for i in range(len(p)): new_p[i] = p[i]
return new_p
def new_colors(p): # first two colors after bg seem to be the "tails"
p[1] = rainbowio.colorwheel( random.randint(0,255) )
p[2] = rainbowio.colorwheel( random.randint(0,255) )
# holds list of sprites,sprite_index,x,y,launch_time
fireworks = [(None,0,0,0, 0) ] * fireworks_count
# make our fireworks
for i in range(len(fireworks)):
pal = copy_palette(sprite_palette)
pal.make_transparent(0) # make background color transparent
x,y = random_xy()
start_index = random.randint(0,sprite_count-1) # pick random point in fireworks life to start
fwsprite = displayio.TileGrid(sprite_sheet, pixel_shader=pal,
width = 1, height = 1,
tile_width = sprite_w, tile_height = sprite_h)
fireworks[i]= (fwsprite, start_index, x, y, pal) # add sprite, and initial index, x,y, palette
maingroup.append(fwsprite)
while True:
for i in range(len(fireworks)):
(sprite, sprite_index, x,y, palette) = fireworks[i] # get firework state
# update firework state
launching = sprite_index == 0 and random.random() < 0.9
if launching:
y = y - 3 # move towards top of screen
else:
sprite_index = sprite_index + 1 # explode!
# firework finished
if sprite_index == sprite_count:
sprite_index = 0 # firework is reborn, make a new x,y for it
x,y = random_xy() #random.randint(dw//4, 3*dw//4), random.randint(dh//2,dh//2+20)
new_colors(palette)
# update firework on screen
sprite[0] = sprite_index # set next sprite in animation
sprite.x, sprite.y = x,y # set its x,y
# save the firework state
fireworks[i] = (sprite, sprite_index, x,y, palette)
time.sleep(0.008) # determines our framerate
@todbot
Copy link
Author

todbot commented Jul 4, 2022

Demo of the above in action on three different platforms:

fireworks_sprites_hdr.mp4

@todbot
Copy link
Author

todbot commented Jul 4, 2022

Sprite sheet is this, but converted to CircuitPython-compatible BMP

fireworks_spritesheet

You can find a converted version of this file in the "bmps" directory here: https://github.com/todbot/circuitpython-tricks/tree/main/larger-tricks/

This was created using the following ImageMagick commands from the original GIF below:

# Reorder gif in Preview.app (I'm sure there's a way in ImageMagick to do this)
# but I wanted gif to start with unexploded ball, so needed to move frames 19-30 to beginning of gif 

# Crop animated gif to remove unused space
convert fireworks_gif_2.gif -coalesce -crop 400x400+55+25 +repage -layers optimize out_animation.gif

# Create long "contact" sheet of all images in the gif, with a black background
montage out_animation.gif -tile x1 -geometry '1x1+0+0<' -alpha On -background 'rgba(0, 0, 0, 1.0)' -quality 100 contact_sheet.png

# Resize contact sheet (it's now 12000 x 400) to a more manageable 1920x64
convert contact_sheet.png -resize x64 fireworks_spritesheet.png

# Convert png to 8-color palletized, non-compressed BMP3
convert fireworks_spritesheet.png -colors 8 -type palette -compress None BMP3:fireworks_spritesheet.bmp

# Copy over to CIRCUITPY drive
cp -X fireworks_spritesheet.bmp /Volumes/CIRCUITPY

The original animated gif this came from is from here: https://opengameart.org/content/fireworks-effect-spritesheet
fireworks_gif_2

@DJDevon3
Copy link

Using this on my 12 panel matrix display. Looks amazing. Excellent code!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment