Making Sprite Sheets
The main key is to save your files as indexed bitmap image files. Then they can be loaded using the CircuitPython Image Load library. Exactly how you do this will depend on what software you are using. The sprite sheets in this guide were created using GIMP. The general process went something like:
- Create new image width x height pixels
- Use 1 pixel pencil tool to draw sprites
- Save as .xcf file for future edits
- When ready to export:
- Image -> Mode -> Indexed
- File -> Export As...
- specify filename with .bmp extension
Flake Fall Speed
So how were different flake fall speeds implemented? Well, pretty simply. The speed is based on the flake index. It comes down to this one line of code (from the fancy version):
flake_pos[i] += 1 - flake[0] / NUM_SPRITES
The first flake falls the fastest. The last flake falls the slowest. That's why the various flake examples arranged the flakes from smallest to largest.
Since the y
location is an integer value, a separate float value is used to allow for floating point math. That is what gets stored in flake_pos
. This is simply changed to an integer when it comes time to set the flake position:
flake.y = int(flake_pos[i])
A fancier way to do this might be to allow for setting custom fall speeds for each flake. But that would require an additional storage mechanism and even more work to manually set up for each flake sprite sheet.
Another idea might be to somehow "weigh" the flake sprite, like how many non-transparent pixels it contains. And then base fall speed on that.
Animated Flakes?
Sure. Why not? That would be pretty cool. This could be done. Maybe in a future version.
Snow Accumulation
It's pretty easy to know when a flake hits the ground. But then what? How do we "add" snow to the currently accumulated snow. The simplest would be to just blindly add a few pixels around where the flake fell. However, this can lead to a "spikey" profile to the snow, which doesn't look very natural.
The current version of the code tries to deal with this, but in a pretty simple way. It does a local steepness check based on the surrounding snow and will only add pixels if it is currently not too steep. This works for the most part, but does lead to somewhat unnatural looking edge effects.
It'd be nice if this were fancier. Another maybe-in-the-future mod. Maybe an avalanche simulator?
Layering in displayio
This project is a good example of how multiple TileGrids
and Groups
can be used to create layered effects and animation. The background image and the snow on the ground are just a single TileGrid
that fills the entire display. The flakes are more interesting. Each flake is a TileGrid
and is only as big as the flake itself. These are all added to the same Group
. All three of these elements, background (TileGrid
), snow (TileGrid
), and flakes (Group
of TileGrid
s), are then added to the main Group
which is shown on the display. As such, the ordering matters in these lines of code:
# Add everything to display splash = displayio.Group() splash.append(background) splash.append(flakes) splash.append(snow) display.show(splash)
Page last edited March 08, 2024
Text editor powered by tinymce.