Once you've finished setting up your MatrixPortal M4 with CircuitPython, you can access the code, audio file, bitmap and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download as a zipped folder.
# SPDX-FileCopyrightText: 2021 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT import time import random import board import pwmio import displayio import adafruit_imageload from audiocore import WaveFile from adafruit_motor import servo from digitalio import DigitalInOut, Direction, Pull from adafruit_matrixportal.matrix import Matrix I2S_VERSION = False # set to True if using I2S audio out # import the appropriate audio module if I2S_VERSION: from audiobusio import I2SOut else: from audioio import AudioOut # setup for down button on matrixportal switch = DigitalInOut(board.BUTTON_DOWN) switch.direction = Direction.INPUT switch.pull = Pull.UP # setup for break beam sensor break_beam = DigitalInOut(board.A1) break_beam.direction = Direction.INPUT break_beam.pull = Pull.UP # pwm for servo servo_pwm = pwmio.PWMOut(board.A4, duty_cycle=2 ** 15, frequency=50) # servo setup servo = servo.Servo(servo_pwm) servo.angle = 90 # import dreidel song audio file wave_file = open("dreidel_song.wav", "rb") wave = WaveFile(wave_file) # setup for audio out if I2S_VERSION: audio = I2SOut(board.A2, board.A3, board.TX) else: audio = AudioOut(board.A0) # setup for matrix display matrix = Matrix(width=32, height=32) display = matrix.display group = displayio.Group() # import dreidel bitmap dreidel_bit, dreidel_pal = adafruit_imageload.load("/dreidel.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) dreidel_grid = displayio.TileGrid(dreidel_bit, pixel_shader=dreidel_pal, width=1, height=1, tile_height=32, tile_width=32, default_tile=0, x=0, y=0) group.append(dreidel_grid) # show dreidel bitmap display.root_group = group timer = 0 # time.monotonic() holder spin = 0 # index for tilegrid speed = 0.1 # rate that bitmap updates clock = 0 # initial time.monotonic() holder to act as time keeper gimel = 3 # bitmap index for gimel, the winning character countdown = 5 # countdown for length of game. default is 5 seconds beam_state = False # state machine for break beam reset = False # state for reset of game dreidel = False # state to track if dreidel game is running clock = time.monotonic() # initial time.monotonic() while True: # debouncing for break beam sensor if not break_beam.value and not beam_state: beam_state = True # if the break beam sensor is triggered or the down button is pressed... if (not break_beam.value and beam_state) or not switch.value: # update break beam state beam_state = False # begin reset for game states reset = True print("pressed") # quick delay time.sleep(0.1) # if reset state... if reset: # hold time.monotonic() value clock = time.monotonic() # reset countdown countdown = 5 # choose random side of dreidel to begin spinning on spin = random.randint(0, 3) # choose random speed spin the dreidel speed = random.uniform(0.05, 0.1) # set game state to True dreidel = True # turn off reset state reset = False # if the game is running... if dreidel: # play the dreidel song audio.play(wave) # while the dreidel song is playing... while audio.playing: # if more time has passed than the random delay setup in reset... if (timer + speed) < time.monotonic(): # dreidel grid index is set to spin value dreidel_grid[0] = spin # spin is increased by 1 spin += 1 # timer is updated to current time timer = time.monotonic() # if a second has passed... if time.monotonic() > (clock + 1): print(clock) print(spin) # the delay is increased to slow down the dreidel speed += 0.05 # clock is set to current time clock = time.monotonic() # countdown value is decreased by 1 countdown -= 1 # if countdown is 0 aka 5 seconds has passed since the start of game... if countdown == 0: # if the bitmap is showing gimel... # you win! if spin is gimel: # the servo turns 90 degrees to dump out chocolate coins servo.angle = 0 # 2 second delay time.sleep(2) # servo turns back to default position for i in range(0, 90, 2): servo.angle = i time.sleep(0.1) # ensures servo is in default position servo.angle = 90 # stop playing the dreidel song audio.stop() # game state is turned off dreidel = False # if you didn't win... else: # the dreidel song stops audio.stop() # game state is turned off dreidel = False # if you are at the end of the sprite sheet... if spin > 3: # index is reset to 0 spin = 0
I2S Audio Version Changes
If you have built the I2S Audio version of the circuit, you will need to change I2S_VERSION
to True before uploading your code.
After downloading the Project Bundle, plug your MatrixPortal M4 into the computer's USB port. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the MatrixPortal M4's CIRCUITPY drive.
- lib folder
- code.py
- dreidel_song.wav
- dreidel.bmp
Your MatrixPortal M4 CIRCUITPY drive should look like this after copying the lib folder and the code.py, dreidel_song.wav and dreidel.bmp files.
The MatrixPortal M4's onboard down button and an IR breakbeam sensor are setup as digital inputs that can be read to start up the dreidel game sequence. If either input is triggered in the loop, then the reset
state is set to True
. This resets all of the game's values to launch a new sequence.
# if the break beam sensor is triggered or the down button is pressed... if (not break_beam.value and beam_state) or not switch.value: # update break beam state beam_state = False # begin reset for game states reset = True print("pressed") # quick delay time.sleep(0.1)
The reset
state acts as a way to make sure everything is ready for a new round of dreidel. Most importantly, the values of spin
and speed
are set to random values. This allows for some variation in how the dreidel spins. spin
affects the first index that is shown in the tilegrid and speed
affects the speed at which the indexes change on the matrix.
# if reset state... if reset: # hold time.monotonic() value clock = time.monotonic() # reset countdown countdown = 5 # choose random side of dreidel to begin spinning on spin = random.randint(0, 3) # choose random speed spin the dreidel speed = random.uniform(0.05, 0.1) # set game state to True dreidel = True # turn off reset state reset = False
When the dreidel
state is True
, then the dreidel song will play through the STEMMA speaker and you'll see the dreidel sprite sheet iterate through the four sides with the different characters.
speed
is used as the delay, with timer
being reset to the current time with each iteration. This lets you avoid using time.sleep()
, which would pause the entire loop.
# if the game is running... if dreidel: # play the dreidel song audio.play(wave) # while the dreidel song is playing... while audio.playing: # if more time has passed than the random delay setup in reset... if (timer + speed) < time.monotonic(): # dreidel grid index is set to spin value dreidel_grid[0] = spin # spin is increased by 1 spin += 1 # timer is updated to current time timer = time.monotonic()
The game is setup to "spin" the dreidel for 5 seconds. With each passing second, the value of speed
is increased by 0.05
seconds. This slows the dreidel down gradually to mimic how it would spin in real life. countdown
keeps track of how many seconds are left in the game.
# if a second has passed... if time.monotonic() > (clock + 1): print(clock) print(spin) # the delay is increased to slow down the dreidel speed += 0.05 # clock is set to current time clock = time.monotonic() # countdown value is decreased by 1 countdown -= 1
Once the game is over, it's determined whether or not you've won the pot of chocolate coins. If the matrix is showing gimel, which is the third index of the sprite sheet, then you've won! As a result, the servo will turn to dump out the chocolate coins for you and then turn back to its default position. The dreidel song will also stop playing and dreidel
is set to False
, stopping the game sequence.
If you didn't win, the song stops playing and the dreidel
state is set to False
, but there isn't any servo action.
# if countdown is 0 aka 5 seconds has passed since the start of game... if countdown == 0: # if the bitmap is showing gimel... # you win! if spin is gimel: # the servo turns 90 degrees to dump out chocolate coins servo.angle = 0 # 2 second delay time.sleep(2) # servo turns back to default position for i in range(0, 90, 2): servo.angle = i time.sleep(0.1) # ensures servo is in default position servo.angle = 90 # stop playing the dreidel song audio.stop() # game state is turned off dreidel = False # if you didn't win... else: # the dreidel song stops audio.stop() # game state is turned off dreidel = False
Text editor powered by tinymce.