Import the Libraries

The code begins by importing the libraries.

import time
import displayio
from adafruit_circuitplayground import cp
import adafruit_imageload
from adafruit_gizmo import tft_gizmo
from adafruit_display_shapes.circle import Circle

Setup the Display

The TFT Gizmo's display is setup.

#  setup for the Gizmo TFT
display = tft_gizmo.TFT_Gizmo()

Graphics: Background and Crescent Moon

The background image and the crescent moon are imported using the adafruit_imageload library.

The crescent moon is a sprite sheet. This allows it to be split into a TileGrid and iterated through so that it appears to be animated.

The background of the crescent moon is black and is made transparent using the make_transparent() function. This lets the crescent moon shape appear by itself in front of the background image.

#  loading the background image
bg_bitmap, bg_palette = adafruit_imageload.load("/clouds_bg.bmp",
                                         bitmap=displayio.Bitmap,
                                         palette=displayio.Palette)
bg_grid = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette)

#  loading the crescent moon bitmap sequence
bitmap, palette = adafruit_imageload.load("/moon_anime.bmp",
                                         bitmap=displayio.Bitmap,
                                         palette=displayio.Palette)
#  makes the black background transparent so we only see the cresent moon
palette.make_transparent(0)

tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette, width = 1, height = 1,
                               tile_height = 120, tile_width = 120,
                               default_tile = 0)

Graphics: Center Jewel

The "jewel" in the center of the locket is made using the adafruit_display_shapes library to create two Circles that are layered.

#  two circles for the center "jewel"
jewel_outline = Circle(x0=120, y0=120, r=40, fill=0xfbf236)
jewel = Circle(x0=120, y0=120, r=35, fill=0xf70570)

Graphics: Groups

With three different graphical elements, a few groups are created to keep them organized. jewel_splash holds the two circles representing the jewel in the center of the display.

#  adding the two jewel circle elements to a group
jewel_splash = displayio.Group(max_size=20)
jewel_splash.append(jewel_outline)
jewel_splash.append(jewel)

moon_group holds the crescent moon sprite sheet and main_group acts as the group with all of the graphical elements.

#  making a group for the crescent moon sequence
#  scale is 2 because at full 240x240 resolution image is too big
moon_group = displayio.Group(scale = 2)
#  group to hold all of the display elements
main_group = displayio.Group()

The order in which the graphics are added to the main_group matters. First, the background image is added, followed by the crescent moon and finally the jewel.

#  adding the crescent moon tile grid to the moon group
moon_group.append(tile_grid)
#  adding the background to the main group
main_group.append(bg_grid)
#  adding the moon group to the main group
main_group.append(moon_group)
#  adding the jewel circles to the main group
main_group.append(jewel_splash)

#  showing the main group on the display
display.root_group = main_group

State Machines

A few state machines are setup. Their functions are commented in the code.

#  tracks the tilegrid index location for the crescent moon
moon = 0
#  holds time.monotonic()
crescent = 0
#  a button debouncing
a_pressed = False
#  b button debouncing
b_pressed = False
#  tracks if music is playing
music_playing = False
#  tracks if animation is paused
animation_pause = False

The Loop

The loop begins by debouncing the Circuit Playground Bluefruit's buttons.

while True:
    #  button debouncing
    if not cp.button_a and a_pressed:
        a_pressed = False
    if not cp.button_b and b_pressed:
        b_pressed = False

Animating the Crescent Moon

An if statement runs the crescent moon animation. Every .8 seconds, the tile_grid advances its index position, showing the next frame of the crescent moon's sprite sheet.

#  runs crescent moon animation
    if not music_playing and not animation_pause:
        #  every .8 seconds...
        if (crescent + .8) < time.monotonic():
            #  the moon animation cycles
            tile_grid[0] = moon
            #  moon is the tilegrid index location
            moon += 1
            #  resets timer
            crescent = time.monotonic()
            #  resets tilegrid index
            if moon > 35:
                moon = 0

Play the Music

The you press the A button on the Circuit Playground Bluefruit, the song will begin playing through the speaker. 

if not music_playing and (cp.button_a and not a_pressed):
        #  music begins playing and will loop
        music_playing = True
        a_pressed = True
        print("music playing")
        #  song plays once
        cp.play_file("moonlight_densetsu.wav")
        #  music_playing state is updated
        music_playing = False

Pause the Animation

If you want to pause the animation to admire the crescent moon, press the B button. The crescent moon will stop rotating.

#  if the animation IS playing and you press the b button...
    if not animation_pause and (cp.button_b and not b_pressed):
        #  the animation pauses by updating the animation_pause state
        animation_pause = True
        b_pressed = True
        #  debugging REPL message
        print("animation paused")

Restart the Animation

To resume the animation, you can press the B button again and the crescent moon will continue its orbit right where it left off.

#  if the animation is PAUSED and you press the b button...
    if animation_pause and (cp.button_b and not b_pressed):
        #  the animation begins again by updating the animation_pause state
        animation_pause = False
        b_pressed = True
        #  debugging REPL message
        print("animation running again")

This guide was first published on Apr 06, 2021. It was last updated on Jun 20, 2024.

This page (CircuitPython Code Walkthrough) was last updated on Mar 08, 2024.

Text editor powered by tinymce.