class GameLoadMenuState(State): def __init__(self, screen, resource_loader): super().__init__() self.screen = screen self.screen_rect = self.screen.get_rect() self.title = 'LOAD A GAME' self.title_textbox = SimpleTextBox(self.screen_rect.centerx, 100, screen, text=self.title, size=72, color='white') self.storage_slot_0 = StorageSlot( 0, self.screen_rect.centerx, self.title_textbox.rect.bottom + 125, 300, 200, screen, callback=self._load_game, text='Free Slot', border=True, hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.confirm_button = SimpleButton( self.screen_rect.centerx, self.storage_slot_0.rect.bottom + 50, 150, 50, screen, text='CONFIRM', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.widgets = [ self.title_textbox, self.confirm_button, self.storage_slot_0 ] self.buttons = [self.confirm_button, self.storage_slot_0] self.buttons_map = {0: "MAIN_MENU_STATE", 1: "STAY"} def _load_game(self): loaded_data = self.storage_slot_0.load_game() self.SHARED_DATA.update(loaded_data) self.SHARED_DATA['GAME_CONTROL']['data_loaded'] = True def get_event(self, event): if event.type == pygame.QUIT: self.is_quit = True else: for button in self.buttons: button.update(event) def update(self): self.title_textbox.update() for idx, button in enumerate(self.buttons): if button.is_clicked: self.next_state = self.buttons_map.get(idx) if self.next_state != "STAY": self.is_done = True button.clear() break else: self.next_state = None def draw(self): self.screen.fill(pygame.Color('black')) for widget in self.widgets: widget.draw()
class GameWinScreenState(State): def __init__(self, screen, resource_loader): super().__init__() self.screen = screen self.screen_rect = self.screen.get_rect() self.title = 'YOU WIN!' self.title_textbox = SimpleTextBox(self.screen_rect.centerx, 100, screen, text=self.title, size=72, color='green') self.play_again_button = SimpleButton( self.screen_rect.centerx, self.title_textbox.rect.bottom + 100, 150, 50, screen, text='PLAY AGAIN!', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.quit_button = SimpleButton( self.screen_rect.centerx, self.play_again_button.rect.bottom + 50, 150, 50, screen, text='QUIT', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.widgets = [ self.title_textbox, self.play_again_button, self.quit_button ] self.buttons = [self.play_again_button, self.quit_button] self.buttons_map = {0: "GAME_COUNTDOWN_STATE", 1: "MAIN_MENU_STATE"} def get_event(self, event): if event.type == pygame.QUIT: self.is_quit = True elif event.type == pygame.KEYDOWN and event.key == pygame.K_p: self.next_state = 'GAME_COUNTDOWN_STATE' self.is_done = True else: for button in self.buttons: button.update(event) def update(self): self.title_textbox.update() for idx, button in enumerate(self.buttons): if button.is_clicked: self.next_state = self.buttons_map.get(idx) self.is_done = True button.clear() break else: self.next_state = None def draw(self): self.screen.fill(pygame.Color('black')) for widget in self.widgets: widget.draw()
class GamePauseMenuState(State): def __init__(self, screen, resource_loader): super().__init__() self.screen = screen self.screen_rect = self.screen.get_rect() self.title = 'GAME PAUSED' self.title_textbox = SimpleTextBox(self.screen_rect.centerx, 100, screen, text=self.title, size=72) self.resume_button = SimpleButton( self.screen_rect.centerx, self.title_textbox.rect.bottom + 100, 150, 50, screen, text='RESUME', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.save_button = SimpleButton( self.screen_rect.centerx, self.resume_button.rect.bottom + 50, 150, 50, screen, text='SAVE', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.quit_button = SimpleButton( self.screen_rect.centerx, self.save_button.rect.bottom + 50, 150, 50, screen, text='QUIT', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.widgets = [ self.title_textbox, self.resume_button, self.save_button, self.quit_button ] self.buttons = [self.resume_button, self.save_button, self.quit_button] self.buttons_map = { 0: "GAME_COUNTDOWN_STATE", 1: "SAVE_MENU_STATE", 2: "MAIN_MENU_STATE" } def get_event(self, event): if event.type == pygame.QUIT: self.is_quit = True elif event.type == pygame.KEYDOWN and event.key == pygame.K_p: self.next_state = 'GAME_COUNTDOWN_STATE' self.is_done = True else: for button in self.buttons: # FIXME: State switch occurs at update (1-switch 2-update current), as buttons are being updated in # get_event() instead of update(), the changes are not applied until the next frame... button.update(event) def update(self): self.title_textbox.update() for idx, button in enumerate(self.buttons): if button.is_clicked: self.next_state = self.buttons_map.get(idx) self.is_done = True button.clear() break else: self.next_state = None def draw(self): self.screen.fill(pygame.Color('black')) for widget in self.widgets: widget.draw()
class GameStateManager(): def __init__(self, states, start_state, screen, caption='Game'): self.clock = pygame.time.Clock() self.screen = screen self.caption = caption self.states = states self.current_state_name = start_state self.current_state = self.states[start_state] self.is_running = True self.is_fps_counter_enabled = False self._fps_counter = SimpleTextBox(650, 10, screen, text='60 fps', size=12) pygame.display.set_caption(self.caption) def _update_fps_counter(self): if self.is_fps_counter_enabled: average_fps = self.clock.get_fps() fps_str = "{0:.2f} fps".format(average_fps) self._fps_counter.modify(newtext=fps_str) self._fps_counter.update() def _draw_fps_counter(self): if self.is_fps_counter_enabled: self._fps_counter.draw() def switch_state(self): next_state_name = self.current_state.next_state self.current_state.clean() self.current_state_name = next_state_name self.current_state = self.states[self.current_state_name] def process_events(self): for event in pygame.event.get(): if event.type == pygame.KEYDOWN and event.key == pygame.K_f: self.is_fps_counter_enabled = not self.is_fps_counter_enabled self.current_state.get_event(event) def update(self): if self.current_state.is_quit: self.is_running = False elif self.current_state.is_done: self.switch_state() self.current_state.update() self._update_fps_counter() def draw(self): self.current_state.draw() self._draw_fps_counter() def run(self): while self.is_running: dt = self.clock.tick(config.FPS) self.process_events() self.update() self.draw() pygame.display.update()
class GameOptionsMenuState(State): def __init__(self, screen, resource_loader): super().__init__() self.screen = screen self.screen_rect = self.screen.get_rect() self.title = 'OPTIONS' self.title_textbox = SimpleTextBox(self.screen_rect.centerx, 100, screen, text=self.title, size=72) self.sound_button = SimpleButton( self.screen_rect.centerx, self.title_textbox.rect.bottom + 100, 150, 50, screen, text='Sound: On', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.back_button = SimpleButton( self.screen_rect.centerx, self.sound_button.rect.bottom + 50, 150, 50, screen, text='BACK', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.widgets = [ self.title_textbox, self.sound_button, self.back_button ] self.buttons = [self.sound_button, self.back_button] self.buttons_map = {0: "TOGGLE_SOUND", 1: "MAIN_MENU_STATE"} self.has_sound = True def _toggle_sound(self): self.has_sound = not self.has_sound if self.has_sound: self.sound_button.textbox.modify(newtext='Sound: On') MuteableSound.unmute_all() else: self.sound_button.textbox.modify(newtext='Sound: Off') MuteableSound.mute_all() def get_event(self, event): if event.type == pygame.QUIT: self.is_quit = True else: for button in self.buttons: button.update(event) def update(self): self.title_textbox.update() for idx, button in enumerate(self.buttons): if button.is_clicked: self.next_state = self.buttons_map.get(idx) if self.next_state is "TOGGLE_SOUND": self._toggle_sound() else: self.is_done = True button.clear() break else: self.next_state = None def draw(self): self.screen.fill(pygame.Color('black')) for widget in self.widgets: widget.draw()
class GameMainMenuState(State): def __init__(self, screen, resource_loader): super().__init__() self.screen = screen self.screen_rect = self.screen.get_rect() self.title = 'PyPong!' self.title_textbox = SimpleTextBox(self.screen_rect.centerx, 100, screen, text=self.title, size=72) self.play_button = SimpleButton( self.screen_rect.centerx, self.title_textbox.rect.bottom + 50, 150, 50, screen, text='PLAY', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.load_button = SimpleButton( self.screen_rect.centerx, self.play_button.rect.bottom + 50, 150, 50, screen, text='LOAD', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.options_button = SimpleButton( self.screen_rect.centerx, self.load_button.rect.bottom + 50, 150, 50, screen, text='OPTIONS', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.exit_button = SimpleButton( self.screen_rect.centerx, self.options_button.rect.bottom + 50, 150, 50, screen, text='EXIT', hovered_sound=resource_loader.get_sound('btn_hover'), clicked_sound=resource_loader.get_sound('btn_click')) self.widgets = [ self.title_textbox, self.play_button, self.load_button, self.options_button, self.exit_button ] self.buttons = [ self.play_button, self.load_button, self.options_button, self.exit_button ] self.buttons_map = { 0: "GAME_COUNTDOWN_STATE", 1: "LOAD_MENU_STATE", 2: "OPTIONS_MENU_STATE", 3: "EXIT" } def get_event(self, event): if event.type == pygame.QUIT: self.is_quit = True else: for button in self.buttons: button.update(event) def update(self): self.title_textbox.update() for idx, button in enumerate(self.buttons): if button.is_clicked: self.next_state = self.buttons_map.get(idx) if self.next_state is "EXIT": self.is_quit = True else: self.is_done = True button.clear() break else: self.next_state = None def draw(self): self.screen.fill(pygame.Color('black')) for widget in self.widgets: widget.draw()