def __init__(self, allsprites, song): self.state = 'prestart' self.allsprites = allsprites self.keyboard_button = [] self.song = song self.font = load_font(song.get_font_filename(), 36) self.notes_are_dropping = False self.song_is_finished = False # Reads and plays audio from notes files self.music_player = MusicPlayer(song, self) # Responsible for loading and animating the background self.background_handler = BackgroundHandler(song) # Assigns falling notes to correct hitbox self.note_dropper = NoteDropper(self.music_player) # Responsible for managing (high) scores self.scoreHandler = ScoreHandler(self.allsprites,self, self.song) # Load sound which plays when a note is missed self.sounds_miss = load_sound(song.get_sound_miss()) # Define Hitboxes input_keys = ['a', 's', 'd', 'f'] self.hitboxes = [ Hitbox('hitbox-example.png', 0, input_keys[0], self.allsprites), Hitbox('hitbox-example.png', 1, input_keys[1], self.allsprites), Hitbox('hitbox-example.png', 2, input_keys[2], self.allsprites), Hitbox('hitbox-example.png', 3, input_keys[3], self.allsprites), ]
def end_screen(): # Keeps track of all sprites to be updated every frame allsprites = pygame.sprite.Group() # Song to be used in game. Only one can be used. song = song_library.example_song_short # Short random song for debugging # song = song_library.example_song_long # Ode To Joy # Create game_state instance, this holds all required game info game_state = GameState(allsprites, song) loop = True replayButton = Button(500, 500, 200, 45, ' Replay', game_state.restart, song.get_font_filename(), allsprites, game_state) mainMenuButton = Button(650, 500, 200, 45, ' Main menu', game_state.menu_start, song.get_font_filename(), allsprites, game_state) top5 = score.get_top5_high_score() while loop: text_font.render_to(screen, (590, 200), "Highscores:", (153, 204, 255)) eventlist = pygame.event.get() for event in eventlist: # Checks if a mouse is clicked if event.type == pygame.MOUSEBUTTONDOWN: replayButton.check_click() mainMenuButton.check_click() quitButton.check_click() # This calls the update() function on all sprites allsprites.update() # Draw Everything screen.blit(game_state.get_background(), (0, 0)) # First draw a new background allsprites.draw(screen) # Next draw all updated sprites pygame.display.update() # Finally render everything to the display
class GameState(): def __init__(self, allsprites, song): self.state = 'prestart' self.allsprites = allsprites self.keyboard_button = [] self.song = song self.font = load_font(song.get_font_filename(), 36) self.notes_are_dropping = False self.song_is_finished = False # Reads and plays audio from notes files self.music_player = MusicPlayer(song, self) # Responsible for loading and animating the background self.background_handler = BackgroundHandler(song) # Assigns falling notes to correct hitbox self.note_dropper = NoteDropper(self.music_player) # Responsible for managing (high) scores self.scoreHandler = ScoreHandler(self.allsprites,self, self.song) # Load sound which plays when a note is missed self.sounds_miss = load_sound(song.get_sound_miss()) # Define Hitboxes input_keys = ['a', 's', 'd', 'f'] self.hitboxes = [ Hitbox('hitbox-example.png', 0, input_keys[0], self.allsprites), Hitbox('hitbox-example.png', 1, input_keys[1], self.allsprites), Hitbox('hitbox-example.png', 2, input_keys[2], self.allsprites), Hitbox('hitbox-example.png', 3, input_keys[3], self.allsprites), ] def restart(self): self.state = 'playing' self.notes_are_dropping = False self.song_is_finished = False self.scoreHandler.restart() self.music_player.restart() def drop_next_note_sprite(self, note): self.note_dropper.drop(note, self.hitboxes) def get_background(self): return self.background_handler.background def end_song(self): self.wait_untill_notes_gone = time.get_ticks() + 2000 self.song_is_finished = True self.notes_are_dropping = True def update(self): self.background_handler.update_background() # While the program is not in the menu it loops through this if self.state == 'playing': # When the song is done and there are no more notes dropping: go to menu if self.song_is_finished and not self.notes_are_dropping: self.state = 'prestart' # When the song is done and there are notes dropping: wait elif self.song_is_finished and self.notes_are_dropping: # After some time assume no more notes are dropping if self.wait_untill_notes_gone < time.get_ticks(): self.notes_are_dropping = False # Otherwise (when song is not finished) keep updating else: self.music_player.update() # Menu loop, which simply doesn't run other code elif self.state == 'prestart': return def check_for_hit(self, hitbox): if hitbox.hits(): self.scoreHandler.change_score(10) else: self.sounds_miss.play() self.scoreHandler.change_score(-5) def add_gpio_pins(self, gpio_pins): for i in range(4): self.hitboxes[i].gpio_event_key = gpio_pins[i]
def main(): # Initialize pygame pygame.init() # Set screen size. Don't change this unless you know what you are doing! screen = pygame.display.set_mode((1280, 720)) # Set the window title pygame.display.set_caption("IAT Challengeweek: Interaction Hero | China") # Keeps track of all sprites to be updated every frame allsprites = pygame.sprite.Group() text_font = pygame.freetype.Font("data/RobotoMono-VariableFont_wght.ttf", 34) # Song to be used in game. Only one can be used. song = song_library.example_song_short # Short random song for debugging # song = song_library.example_song_long # Ode To Joy # Create game_state instance, this holds all required game info game_state = GameState(allsprites, song) # Checks if the program is running on a Raspberry Pi is_running_on_rpi = utils.is_running_on_rpi() if is_running_on_rpi: # Below are some pin input numbers, feel free to change them. However, # !!! ALWAYS READ THE PIN DOCUMENTATION CAREFULLY !!! # Pay special attention to the difference between GPIO pin numbers and BOARD pin numbers # For example GPIO17 is addressed 17 rather than 11 (See pin numbering diagram.) # https://gpiozero.readthedocs.io/en/stable/recipes.html#pin-numbering gpio_pin_numbers = [2, 3, 4, 17] # Max 4 pins gpio_buttons = init_rpi_buttons(gpio_pin_numbers) game_state.add_gpio_pins(gpio_pin_numbers) # Prepare game objects clock = pygame.time.Clock() startButton = Button(500, 300, 140, 40, ' Start', game_state.restart, song.get_font_filename(), allsprites, game_state) quitButton = Button(500, 350, 140, 40, ' Quit', quit, song.get_font_filename(), allsprites, game_state) # easyButton = Button(450, 250, 140, 40, ' Easy', select_difficulty, song.get_font_filename(), allsprites, game_state) # normalButton = Button(600, 250, 140, 40, ' Normal', select_difficulty, song.get_font_filename(), allsprites, game_state) # hardButton = Button(750, 250, 140, 40, ' Hard', select_difficulty, song.get_font_filename(), allsprites, game_state) # Main loop going = True while going: # Update the clock, argument is max fps clock.tick(60) # Every 'tick' or programcycle the gamestate update() is called game_state.update() # Get all events from the last cycle and store them as variable # This is stored as a variable because pygame.even.get() empties this list eventlist = pygame.event.get() # Check if there are any global quit events for event in eventlist: # If yes, the game loop won't start again if event.type == pygame.QUIT: going = False elif event.type == pygame.KEYDOWN and event.unicode == pygame.K_ESCAPE: going = False # This runs before the user starts the game if game_state.state == 'prestart': for event in eventlist: # Checks if a mouse is clicked if event.type == pygame.MOUSEBUTTONDOWN: startButton.check_click() quitButton.check_click() # Difficulty buttons # easyButton.check_click() # normalButton.check_click() # hardButton.check_click() # This runs when the users starts a game elif game_state.state == 'playing': stopButton = Button(100, 100, 140, 40, ' Stop', game_state.menu_start, song.get_font_filename(), allsprites, game_state) # Loop through all potential hitboxes for hitbox in game_state.hitboxes: # Every hitbox needs to check all events for event in eventlist: if event.type == pygame.KEYDOWN and event.unicode == hitbox.event_key: game_state.check_for_hit(hitbox) elif event.type == pygame.KEYUP: hitbox.unpunch() elif event.type == pygame.MOUSEBUTTONDOWN: stopButton.check_click() # When on RPi also check for GPIO input if is_running_on_rpi: for button in gpio_buttons: # When a buttons is pressed in this loop and wasn't pressed in the last loop if button.is_pressed( ) and button.gpio_key is hitbox.gpio_event_key and button.is_available( ): button.use( ) # Set the button as unavailable for the next loop game_state.check_for_hit(hitbox) # When a button was not pressed in this loop elif not button.is_pressed(): button.wake() # Set the button as available again hitbox.unpunch() # elif game_state.state == 'end_game': # going = False # end_screen() # End state elif game_state.state == 'end_game': replayButton = Button(500, 500, 200, 45, ' Replay', game_state.restart, song.get_font_filename(), allsprites, game_state) mainMenuButton = Button(650, 500, 200, 45, ' Main menu', game_state.menu_start, song.get_font_filename(), allsprites, game_state) top5 = score.get_top5_high_score() text_font.render_to(screen, (500, 200), "top 5 Score:", (0, 0, 0)) height = 250 for count, top in enumerate(top5): h = height + 30 * count text_font.render_to(screen, (500, h), str(top), (0, 0, 0)) # text_font.render_to(screen, (500, 250), "ss", (153, 204, 255)) # [90, 70, 65, 60, 60] for event in eventlist: # Checks if a mouse is clicked if event.type == pygame.MOUSEBUTTONDOWN: replayButton.check_click() mainMenuButton.check_click() quitButton.check_click() # text_font.render_to(screen, (40, 350), "Hello World!", (0, 0, 0)) # This calls the update() function on all sprites allsprites.update() pygame.display.flip() # Draw Everything screen.blit(game_state.get_background(), (0, 0)) # First draw a new background allsprites.draw(screen) # Next draw all updated sprites pygame.display.update() # Finally render everything to the display