|
| 1 | +import displayio |
| 2 | +from blinka_displayio_pygamedisplay import PyGameDisplay |
| 3 | +import pygame |
| 4 | +import time |
| 5 | +import random |
| 6 | +from adafruit_display_text import label |
| 7 | +from adafruit_bitmap_font import bitmap_font |
| 8 | + |
| 9 | +# Load a custom font with a smaller size |
| 10 | +font = bitmap_font.load_font("Arial-12.bdf") |
| 11 | + |
| 12 | +# Initialize pygame and display |
| 13 | +pygame.init() |
| 14 | +pygame.mixer.init() # Initialize the mixer module for sound |
| 15 | +display = PyGameDisplay(width=128, height=128) |
| 16 | +splash = displayio.Group() |
| 17 | +display.show(splash) |
| 18 | + |
| 19 | +# Helper function to load bitmaps |
| 20 | +def load_bitmap(file_name): |
| 21 | + try: |
| 22 | + return displayio.OnDiskBitmap(file_name) |
| 23 | + except FileNotFoundError: |
| 24 | + print(f"Error: {file_name} not found") |
| 25 | + return None |
| 26 | + |
| 27 | +# Load resources |
| 28 | +cat_sheet = load_bitmap("uiia_spritesheet.png") |
| 29 | +left_beat_bitmap = load_bitmap("beat_left.bmp") |
| 30 | +mid_beat_bitmap = load_bitmap("beat_mid.bmp") |
| 31 | +right_beat_bitmap = load_bitmap("beat_right.bmp") |
| 32 | +line_map = load_bitmap("line.bmp") |
| 33 | + |
| 34 | +# Ensure all bitmaps are loaded |
| 35 | +if not all([cat_sheet, left_beat_bitmap, mid_beat_bitmap, right_beat_bitmap, line_map]): |
| 36 | + print("Error: One or more bitmap files are missing.") |
| 37 | + pygame.quit() |
| 38 | + exit() |
| 39 | + |
| 40 | +# Background colors for disco effect |
| 41 | +disco_colors = [(139, 0, 0), (255, 69, 0), (255, 140, 0), (255, 215, 0), (0, 100, 0), (0, 0, 139), (75, 0, 130), (139, 0, 139)] |
| 42 | + |
| 43 | +# Create a solid color bitmap for the background |
| 44 | +background_bitmap = displayio.Bitmap(display.width, display.height, 1) |
| 45 | +background_palette = displayio.Palette(1) |
| 46 | +background_palette[0] = disco_colors[0] # Initial color |
| 47 | +background_sprite = displayio.TileGrid(background_bitmap, pixel_shader=background_palette) |
| 48 | +splash.append(background_sprite) |
| 49 | + |
| 50 | +# Function to change background color |
| 51 | +def change_background_color(): |
| 52 | + color = random.choice(disco_colors) |
| 53 | + background_palette[0] = color |
| 54 | + |
| 55 | +# Load the bitmap image |
| 56 | +cat_sheet = displayio.OnDiskBitmap("uiia_spritesheet.png") |
| 57 | +cat_sprite = displayio.TileGrid( |
| 58 | + cat_sheet, |
| 59 | + pixel_shader=cat_sheet.pixel_shader, |
| 60 | + width=1, |
| 61 | + height=1, |
| 62 | + tile_width=cat_sheet.width // 8, # Assuming 8 frames in the sprite sheet |
| 63 | + tile_height=cat_sheet.height, |
| 64 | + x=(display.width - cat_sheet.width // 8) // 2, |
| 65 | + y=display.height - cat_sheet.height - 10 |
| 66 | +) |
| 67 | +splash.append(cat_sprite) |
| 68 | + |
| 69 | +# Load beat bitmaps |
| 70 | +left_beat_bitmap = displayio.OnDiskBitmap("beat_left.bmp") |
| 71 | +mid_beat_bitmap = displayio.OnDiskBitmap("beat_mid.bmp") |
| 72 | +right_beat_bitmap = displayio.OnDiskBitmap("beat_right.bmp") |
| 73 | +beats = [] |
| 74 | + |
| 75 | +# Load the sound effect |
| 76 | +score_sound = pygame.mixer.Sound("snare.wav") |
| 77 | + |
| 78 | +# Load and play the background song |
| 79 | +pygame.mixer.music.load("oiia.mp3") |
| 80 | +pygame.mixer.music.play() # Play the song once |
| 81 | + |
| 82 | +# Variables to control the rate of beats being spawned and speed of beats falling down |
| 83 | +spawn_interval = 0.5 # Time interval between spawns in seconds |
| 84 | +fall_speed = 12 # Speed of beats falling down (pixels per frame) |
| 85 | +score = 0 # Initialize score |
| 86 | +total_beats_spawned = 0 # Initialize total beats spawned |
| 87 | +collision_tolerance = 10 # Tolerance for collision detection |
| 88 | + |
| 89 | +# Animation variables |
| 90 | +animation_interval = 0.1 # Time interval between animation frames in seconds |
| 91 | +last_animation_time = time.time() |
| 92 | +current_frame = 0 |
| 93 | +num_frames = 8 # Number of frames in the sprite sheet |
| 94 | + |
| 95 | +# Function to spawn a random beat |
| 96 | +def spawn_beat(): |
| 97 | + global total_beats_spawned |
| 98 | + beat_bitmap = random.choice([left_beat_bitmap, mid_beat_bitmap, right_beat_bitmap]) |
| 99 | + if beat_bitmap == left_beat_bitmap: |
| 100 | + x_position = 9 |
| 101 | + elif beat_bitmap == mid_beat_bitmap: |
| 102 | + x_position = 61 |
| 103 | + else: |
| 104 | + x_position = 113 |
| 105 | + beat = displayio.TileGrid( |
| 106 | + beat_bitmap, |
| 107 | + pixel_shader=beat_bitmap.pixel_shader, |
| 108 | + width=1, |
| 109 | + height=1, |
| 110 | + tile_width=beat_bitmap.width, |
| 111 | + tile_height=beat_bitmap.height, |
| 112 | + x=x_position, |
| 113 | + y=-32 |
| 114 | + ) |
| 115 | + beats.append(beat) |
| 116 | + splash.append(beat) |
| 117 | + total_beats_spawned += 1 |
| 118 | + change_background_color() # Change background color on each beat spawn |
| 119 | + |
| 120 | +# Load the bitmap image of beatline |
| 121 | +line_map = displayio.OnDiskBitmap("line.bmp") |
| 122 | + |
| 123 | +# Create a TileGrid to hold the image |
| 124 | +linemap = displayio.TileGrid( |
| 125 | + line_map, |
| 126 | + pixel_shader=line_map.pixel_shader, |
| 127 | + width=1, |
| 128 | + height=1, |
| 129 | + tile_width=line_map.width, # Ensure this matches the bitmap's width |
| 130 | + tile_height=line_map.height, # Ensure this matches the bitmap's height |
| 131 | + x=(display.width - line_map.width) // 2, |
| 132 | + y=display.height - line_map.height - 10 |
| 133 | +) |
| 134 | +splash.append(linemap) |
| 135 | + |
| 136 | +# Create a label to display the final score |
| 137 | +score_label = label.Label(font, text="", color=0xFFFFFF, x=10, y=10) |
| 138 | +splash.append(score_label) |
| 139 | + |
| 140 | +def main_loop(): |
| 141 | + global running, paused, last_spawn_time, score, total_beats_spawned, last_animation_time, current_frame |
| 142 | + while running: |
| 143 | + current_time = time.time() |
| 144 | + |
| 145 | + if not paused and current_time - last_spawn_time > spawn_interval: |
| 146 | + spawn_beat() |
| 147 | + last_spawn_time = current_time |
| 148 | + |
| 149 | + for event in pygame.event.get(): |
| 150 | + if event.type == pygame.QUIT: |
| 151 | + running = False |
| 152 | + paused = True |
| 153 | + pygame.mixer.music.pause() |
| 154 | + elif event.type == pygame.KEYDOWN: |
| 155 | + if paused: |
| 156 | + if event.key == pygame.K_RIGHT: |
| 157 | + paused = False |
| 158 | + pygame.mixer.music.unpause() |
| 159 | + elif event.key == pygame.K_LEFT: |
| 160 | + running = False |
| 161 | + else: |
| 162 | + print(f"Key pressed: {pygame.key.name(event.key)}") # Print the key pressed for debugging |
| 163 | + correct_key_pressed = False |
| 164 | + for beat in beats: |
| 165 | + if abs(beat.y - linemap.y) <= collision_tolerance: |
| 166 | + if (event.key == pygame.K_LEFT and beat.x == 9) or \ |
| 167 | + (event.key == pygame.K_DOWN and beat.x == 61) or \ |
| 168 | + (event.key == pygame.K_RIGHT and beat.x == 113): |
| 169 | + score += 1 |
| 170 | + beats.remove(beat) |
| 171 | + splash.remove(beat) |
| 172 | + score_sound.play() # Play the sound effect |
| 173 | + print(f"Score: {score}") |
| 174 | + correct_key_pressed = True |
| 175 | + break |
| 176 | + if not correct_key_pressed: |
| 177 | + score -= 1 |
| 178 | + print(f"Score: {score}") |
| 179 | + |
| 180 | + if not paused: |
| 181 | + # Move beats down |
| 182 | + for beat in beats: |
| 183 | + beat.y += fall_speed |
| 184 | + if beat.y > display.height: |
| 185 | + beats.remove(beat) |
| 186 | + splash.remove(beat) |
| 187 | + |
| 188 | + # Update the display |
| 189 | + score_label.text = f"Score: {score}/{total_beats_spawned}" |
| 190 | + display.refresh() |
| 191 | + |
| 192 | + # Check if the music has stopped |
| 193 | + if not pygame.mixer.music.get_busy(): |
| 194 | + running = False |
| 195 | + |
| 196 | + # Update animation |
| 197 | + if current_time - last_animation_time > animation_interval: |
| 198 | + current_frame = (current_frame + 1) % num_frames |
| 199 | + cat_sprite[0] = current_frame |
| 200 | + last_animation_time = current_time |
| 201 | + |
| 202 | + # Delay to control frame rate |
| 203 | + time.sleep(0.1) |
| 204 | + |
| 205 | +while True: |
| 206 | + running = True |
| 207 | + paused = False |
| 208 | + last_spawn_time = time.time() |
| 209 | + score = 0 |
| 210 | + total_beats_spawned = 0 |
| 211 | + beats.clear() |
| 212 | + splash = displayio.Group() |
| 213 | + display.show(splash) |
| 214 | + splash.append(background_sprite) |
| 215 | + splash.append(cat_sprite) |
| 216 | + splash.append(linemap) |
| 217 | + pygame.mixer.music.rewind() |
| 218 | + pygame.mixer.music.play() |
| 219 | + |
| 220 | + main_loop() |
| 221 | + |
| 222 | + # Clear the screen and display the final score |
| 223 | + splash = displayio.Group() |
| 224 | + display.show(splash) |
| 225 | + final_score_text = f"Final Score: \n{score}/{total_beats_spawned}Replay?\nRight for Yes\nLeft for No" |
| 226 | + final_score_label = label.Label(font, text=final_score_text, color=0xFFFFFF, x=10, y=display.height // 2 - 40, scale=1) |
| 227 | + splash.append(final_score_label) |
| 228 | + display.refresh() |
| 229 | + |
| 230 | + # Wait for user input for replay |
| 231 | + replay = None |
| 232 | + while replay is None: |
| 233 | + for event in pygame.event.get(): |
| 234 | + if event.type == pygame.QUIT: |
| 235 | + replay = False |
| 236 | + elif event.type == pygame.KEYDOWN: |
| 237 | + if event.key == pygame.K_RIGHT: |
| 238 | + replay = True |
| 239 | + elif event.key == pygame.K_LEFT: |
| 240 | + replay = False |
| 241 | + |
| 242 | + if not replay: |
| 243 | + break |
| 244 | + |
| 245 | +pygame.quit() |
0 commit comments