# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT import time from random import randint from micropython import const import board import terminalio import displayio import adafruit_imageload import digitalio import simpleio from keypad import ShiftRegisterKeys, Event from adafruit_display_text import label # setup for PyBadge buttons BUTTON_LEFT = const(7) BUTTON_UP = const(6) BUTTON_DOWN = const(5) BUTTON_RIGHT = const(4) BUTTON_SEL = const(3) BUTTON_START = const(2) BUTTON_A = const(1) BUTTON_B = const(0) pad = ShiftRegisterKeys(clock=board.BUTTON_CLOCK, data=board.BUTTON_OUT, latch=board.BUTTON_LATCH, key_count=8, value_when_pressed=True, max_events=1) latest_event = Event(key_number=8) last_read = 0 # enables speaker speakerEnable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) speakerEnable.switch_to_output(value=True) # Sprite cell values EMPTY = 0 BLINKA_1 = 1 BLINKA_2 = 2 SPARKY = 3 HEART = 4 JUMP_1 = 5 JUMP_2 = 6 # creates display display = board.DISPLAY # scale=2 allows the sprites to be bigger group = displayio.Group(scale=2) # Blinka sprite setup blinka, blinka_pal = adafruit_imageload.load("/spritesNew.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) # creates a transparent background for Blinka blinka_pal.make_transparent(7) blinka_grid = displayio.TileGrid(blinka, pixel_shader=blinka_pal, width=2, height=1, tile_height=16, tile_width=16, default_tile=EMPTY) blinka_grid.x = 0 blinka_grid.y = 32 blinka_group = displayio.Group() blinka_group.append(blinka_grid) # first Sparky sprite sparky0, sparky0_pal = adafruit_imageload.load("/spritesNew.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) sparky0_pal.make_transparent(7) sparky0_grid = displayio.TileGrid(sparky0, pixel_shader=sparky0_pal, width=1, height=1, tile_height=16, tile_width=16, default_tile=SPARKY) # all Sparky sprites begin off screen sparky0_grid.x = 100 sparky0_grid.y = 32 sparky0_group = displayio.Group() sparky0_group.append(sparky0_grid) # 2nd Sparky sprite sparky1, sparky1_pal = adafruit_imageload.load("/spritesNew.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) sparky1_pal.make_transparent(7) sparky1_grid = displayio.TileGrid(sparky1, pixel_shader=sparky1_pal, width=1, height=1, tile_height=16, tile_width=16, default_tile=SPARKY) sparky1_grid.x = 100 sparky1_grid.y = 32 sparky1_group = displayio.Group() sparky1_group.append(sparky1_grid) # 3rd Sparky sprite sparky2, sparky2_pal = adafruit_imageload.load("/spritesNew.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) sparky2_pal.make_transparent(7) sparky2_grid = displayio.TileGrid(sparky2, pixel_shader=sparky2_pal, width=1, height=1, tile_height=16, tile_width=16, default_tile=SPARKY) sparky2_grid.x = 100 sparky2_grid.y = 32 sparky2_group = displayio.Group() sparky2_group.append(sparky2_grid) # heart sprite group life_bit, life_pal = adafruit_imageload.load("/spritesNew.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) life_grid = displayio.TileGrid(life_bit, pixel_shader=life_pal, width=3, height=1, tile_height=16, tile_width=16, default_tile=HEART) life_group = displayio.Group() life_group.append(life_grid) # adding all graphics groups to the main display group group.append(blinka_group) group.append(sparky0_group) group.append(sparky1_group) group.append(sparky2_group) group.append(life_group) # text area for the running score score_text = " " font = terminalio.FONT score_color = 0x0000FF # text for "game over" graphic game_over_text = label.Label(font, text = " ", color = 0xFF00FF) # score text score_area = label.Label(font, text=score_text, color=score_color) # text for "new game" graphic new_game_text = label.Label(font, text = " ", color = 0xFF00FF) # coordinants for text areas score_area.x = 57 score_area.y = 6 game_over_text.x = 13 game_over_text.y = 30 new_game_text.x = 8 new_game_text.y = 30 # creating a text display group text_group = displayio.Group() text_group.append(score_area) text_group.append(game_over_text) text_group.append(new_game_text) # adding text group to main display group group.append(text_group) # displaying main display group display.root_group = group # state for hit detection crash = False # states to see if a Sparky is on screen sparky0 = False sparky1 = False sparky2 = False # array of Sparky states sparky_states = [sparky0, sparky1, sparky2] # array of x location for Sparky's sparky_x = [sparky0_grid.x, sparky1_grid.x, sparky2_grid.x] # function to display the heart sprites for lives def life(): for _ in range(0, 3): life_grid[_, 0] = EMPTY for hearts in range(life_count): life_grid[hearts, 0] = HEART # lives at beginning of the game life_count = 3 # variables for scoring jump_score = 0 total_score = 0 bonus = 0 # state for Blinka being in default 'slither' mode snake = True # state to check if Blinka has jumped over Sparky cleared = False # state for the end of a game end = False # state for a new game beginning new_game = True # state for detecting game over game_over = False # variable to change between Blinka's two slither sprites b = 1 # variable to hold time.monotonic() count for Blinka slither animation slither = 0 # variables to hold time.monotonic() count to delay Sparky spawning blue = 0 smoke = 0 monster = 0 # jump button press state jump_pressed = False while True: # checks if button has been pressed if (last_read + 0.01) < time.monotonic(): pad.events.get_into(latest_event) last_read = time.monotonic() # new game if new_game and not game_over: # graphics for new game splash screen blinka_grid.y = 16 blinka_grid[0] = JUMP_1 blinka_grid[1] = JUMP_2 sparky0_grid.x = 5 sparky1_grid.x = 40 sparky2_grid.x = 65 score_area.text = str(300) new_game_text.text = "BLINKA JUMP" life() # if start is pressed... if latest_event: if latest_event.key_number == BUTTON_START: # prepares display for gameplay print("start game") new_game_text.text = " " life_count = 3 start = time.monotonic() new_game = False end = False sparky0_grid.x = 100 sparky1_grid.x = 100 sparky2_grid.x = 100 # if game has started... if not game_over and not new_game: # gets time.monotonic() to have a running score mono = time.monotonic() score = mono - start # adds 10 points every time a Sparky is cleared total_score = score + jump_score # displays score as text score_area.text = str(int(total_score)) # puts Sparky states and x location into callable arrays for s in range(3): sparky_state = sparky_states[s] sparky_location = sparky_x[s] # Sparkys are generated using a staggered delay # and matching an int to a random int # 1st Sparky if (blue + 0.03) < time.monotonic(): if randint(1, 15) == 3: sparky_states[0] = True blue = time.monotonic() # 2nd Sparky if (smoke + 0.07) < time.monotonic(): if randint(1, 15) == 7: sparky_states[1] = True smoke = time.monotonic() # 3rd Sparky if (monster + 0.12) < time.monotonic(): if randint(1, 15) == 12: sparky_states[2] = True monster = time.monotonic() # if a Sparky is generated, it scrolls across the screen 1 pixel at a time # 1st Sparky if sparky_states[0] is True: sparky0_grid.x -= 1 sparky_x[0] = sparky0_grid.x display.refresh(target_frames_per_second=120) # when a Sparky is 16 pixels off the display, # it goes back to its starting position if sparky0_grid.x is -16: sparky_states[0] = False sparky0_grid.x = 100 sparky_x[0] = sparky0_grid.x # 2nd Sparky if sparky_states[1] is True: sparky1_grid.x -= 1 sparky_x[1] = sparky1_grid.x display.refresh(target_frames_per_second=120) if sparky1_grid.x is -16: sparky_states[1] = False sparky1_grid.x = 100 sparky_x[1] = sparky1_grid.x # 3rd Sparky if sparky_states[2] is True: sparky2_grid.x -= 1 sparky_x[2] = sparky2_grid.x display.refresh(target_frames_per_second=120) if sparky2_grid.x is -16: sparky_states[2] = False sparky2_grid.x = 100 sparky_x[2] = sparky2_grid.x # if no lives are left then the game ends if life_count is 0: game_over = True # if the A button is pressed then Blinka is no longer in the default # slither animation aka she jumps if latest_event.key_number == BUTTON_A: if latest_event.pressed: jump_pressed = True snake = False else: jump_pressed = False snake = True # heart sprites are displayed to show life count life() # if Blinka is slithering... if snake: # Blinka default location blinka_grid.y = 32 # empty 2nd tile so that the jump sprite can be shown using # the same tilegrid blinka_grid[1] = EMPTY # every .15 seconds Blinka's slither sprite changes # so that her slithering is animated # b holds tilegrid position to display correct sprite if (slither + 0.15) < time.monotonic(): blinka_grid[0] = b b += 1 slither = time.monotonic() if b > 2: b = 1 # if a Sparky collides with Blinka while she is slithering... for s in range(3): if sparky_x[s] == 8 and blinka_grid.y == 32: # tone is played simpleio.tone(board.SPEAKER, 493.88, 0.05) simpleio.tone(board.SPEAKER, 349.23, 0.05) # lose a life life_count = life_count - 1 # if the A button is pressed then... else: # Blinka JUMPS # y location changes one row up and both jump sprites are shown blinka_grid.y = 16 blinka_grid[0] = JUMP_1 blinka_grid[1] = JUMP_2 # if Blinka jumps over a Sparky... for j in range(3): if sparky_x[j] == 8 and not cleared: # 10 points to the player bonus += 1 jump_score = bonus * 10 cleared = True # special victory tone is played simpleio.tone(board.SPEAKER, 523.25, 0.005) simpleio.tone(board.SPEAKER, 783.99, 0.005) if not jump_pressed: # resets back to Blinka animation snake = True # resets that Blinka has not jumped over a Sparky cleared = False # if there are no more lives, the game is over if game_over and not new_game: # game over text is displayed game_over_text.text = "GAME OVER" score_area.text = " " # end game tone is played # and then the screen holds with the last # sprites on screen and game over text if not end: simpleio.tone(board.SPEAKER, 220, 0.05) simpleio.tone(board.SPEAKER, 207.65, 0.05) simpleio.tone(board.SPEAKER, 196, 0.5) end = True # if the start button is pressed... if latest_event and game_over: if latest_event.key_number == BUTTON_START: # display, states and score are reset for gameplay game_over_text.text = " " life_count = 3 start = time.monotonic() game_over = False end = False total_score = 0 jump_score = 0 bonus = 0 score = 0 blue = 0 smoke = 0 monster = 0 sparky0_grid.x = 100 sparky1_grid.x = 100 sparky2_grid.x = 100 # game begins again with all Sparky's off screen