The code for the game is thoroughly commented with explanations of what each line or section are for. This page will provide a higher level summary of the major components.
Hardware Principals
This game is designed around two primary hardware peripherals: the HSTX connector with a DVI breakout for the display, and a basic USB keyboard for the player control input.
HSTX Display
To initialize the display the built-in core modules picodvi
, and framebufferio
are used. These modules support a few different resolutions and color depths. This project is made for the 320x240 resolution with 16 bit color depth. The pixels are automatically doubled before being pushed to the display so it will come out as 640x480, depending on your monitor or TV, it may further upscale it to fit the screen.
USB Keyboard
USB Host is relatively new to CircuitPython, first coming on Raspberry Pi RP2040-based boards.
Typically, one would access a USB port by:
- Establishing the USB connection
- Reading USB Reports, sections of bytes sent when an action occurs on the peripheral like a key is pressed or joystick moved.
- Parsing the reports and providing meaningful input to the program.
Python has the concept of standard input and output streams, similar to those in Linux/Unix and other operating systems. CircuitPython has this capability and through a lot of behind the scenes code, presents a USB keyboard as a stdin input device. The code to get USB Host Keyboard characters and echo them to serial out is as follows:
import supervisor import sys while True: available = supervisor.runtime.serial_bytes_available if available: c = sys.stdin.read(available) print(c, end='')
As an added bonus this also means that the game can be played via the USB Serial connection with your PC. Simply connect to your device with your preferred serial console application, make sure the app has focus and anything you type on your PC keyboard gets sent to CircuitPython via the same stdin
stream it's reading keyboard keys from.
Helper Classes
The game code has 3 helper classes which contain behavior for various parts of the game bundled together as easy to use component objects.
Post
The Post
class extends displayio.Group
so it can contain TileGrid
s and other visual elements to be shown on the display. While it's name is Post
singular, it actually holds a pair of visual posts, one at the top of the screen, and the other at the bottom. In the original flappy bird, these were green pipes. The check_collision()
function will determine if the cat sprite is colliding with either of the posts in this Post
instance. These Post
objects get moved along the screen by updating the x
coordinate to lower values for each fame of the game.
PostPool
PostPool
is a "grab bag" of Post
s to store the ones not currently in use, and provide one for us randomly when we need to add a new one to the right edge of the display. The get_post()
and recycle_post()
functions are used to get an unused Post
, and then recycle it back into the pool when it's no longer needed.
GameOverException
This is a basic custom exception that the code will raise when the player loses by touching a scratching post, or the top or bottom edges of the screen.
Helper Functions
The game code has 5 helper functions which carry out some of the game play functionality. Each is listed below with a brief description of it's purpose.
-
swap_trail()
- Swap the trail back and forth between rainbow and trans flag colors. -
draw_trail()
- Draw the trail at the current location. -
erase_trail()
- Erase the trail at the current location. -
shift_trail()
- Shift the pixel locations in the trail to the left by one. -
shift_post()
- Move the posts to the left by one step.
Display Elements
The display elements are broken up into a few different Group
s with different scale factors applied. Each is listed below with a brief description of what it holds.
-
main_group
- The top level displayioGroup
that holds everything else within the game. ThePost
objects are added directly to this group, and are the only display element that is rendered at 1:1 size instead of scaled up by aGroup
. -
scaled_group
- ThisGroup
gets scaled 2x. It holds the background, the cat sprite, and the trail canvas group. -
bg_group
- This is scaled by 10x and put inside ofscaled_group
for an additional 2x making the total scale factor20
. That allows it to contain a very small Bitmap with the dark blue background, but scale it all the way up to match the display size. -
canvas_group
- This group is scaled 2x, and is placed inside of thescaled_group
which brings the total scaling factor to4
. It holds the trail canvas Bitmap that the trail pixels are rendered into. -
trail_bmp
- A Bitmap that is 1px wide and 6px tall. It holds one column of the trail. It's contents will get copied into the canvasBitmap
withbitmaptools.blit()
. -
nyan_tg
- ThisTileGrid
holds the cat sprite that represents the player. It's y location is changed in accordance with the gravity calculation, and jump button. It'sx
location remains static. -
score_lbl
- A text label that goes in the bottom left corner and shows the current score. -
game_over_lbl
- A text label that gets splashed on top of the game when the player loses.
Page last edited March 13, 2025
Text editor powered by tinymce.