class Speaker(pygame_gui.elements.UIWindow): def __init__(self, pos, manager): super().__init__( pygame.Rect(pos, (400, 128)), manager=manager, window_display_title="speaker", object_id="#speaker", ) self.label = UILabel( relative_rect=pygame.Rect(-20, 10, 400, 20), text="", manager=manager, container=self, ) self.input = UITextEntryLine(relative_rect=pygame.Rect(0, 40, 368, 30), manager=manager, container=self) self.engine = pyttsx3.init() self.engine.setProperty("rate", 150) self.speakthrd = None def process_event(self, event): super().process_event(event) if event.type == pygame.USEREVENT and event.ui_element == self.input and event.user_type == pygame_gui.UI_TEXT_ENTRY_FINISHED and ( self.speakthrd is None or not self.speakthrd.is_alive()) and self.input.get_text != "": self.engine.say(self.input.get_text) self.speakthrd = threading.Thread(target=self.engine.runAndWait, args=()) self.speakthrd.start() self.label.set_text(self.input.get_text) self.input.set_text("")
class TextValueLabel(object): def __init__(self, text_rect: pygame.rect.Rect, text, value, manager, container): self.ui_manager = manager self.text_rect = text_rect self.container = container self.text = text self.value = value self.text_label = UILabel(self.text_rect, text, manager=self.ui_manager, container=self.container) self.value_label = UILabel(pygame.Rect( (self.text_rect.x, self.text_rect.y + self.text_rect.height), (self.text_rect.width, self.text_rect.height)), value, manager=self.ui_manager, container=self.container) def set_value(self, value): self.value = value self.value_label.set_text(value) def set_text(self, text): self.text = text self.text_label.set_text(text)
class Label(ColorElement): def __init__(self, text, layout_info, container, text_color=BLACK, background_color=TRANSPARENT, padding=None): super().__init__(layout_info, container, padding) self.text = text self.element = UILabel(relative_rect=self.bounds, manager=self.manager, text=text) self.text_color = text_color self.background_color = background_color def set_text(self, text): self.text = text self.element.set_text(text) @property def text_color(self): return self.element.text_colour @text_color.setter def text_color(self, color): if color is None: return self.element.text_colour = color self.element.rebuild()
class SpeakSpell(pygame_gui.elements.UIWindow): speakthrd = None def __init__(self, pos, manager): super().__init__( pygame.Rect(pos, (400,128)), manager=manager, window_display_title='speaknspell', object_id='#speaknspell' ) self.label = UILabel( relative_rect=pygame.Rect(-20, 10, 400, 20), text='', manager=manager, container=self ) self.input = UITextEntryLine( relative_rect=pygame.Rect(0, 40, 368, 30), manager=manager, container=self ) self.engine = pyttsx3.init() self.engine.setProperty('rate', 150) self.speakthrd = None self.speak('Hello, thank you for using snakeware!') def speak(self, text): if self.speakthrd is not None and self.speakthrd.is_alive(): return if text == '': return self.engine.say(text) self.speakthrd = threading.Thread(target=self.engine.runAndWait, args=()) self.speakthrd.start() self.label.set_text(text) self.input.set_text('') def process_event(self, event): super().process_event(event) if event.type == pygame.USEREVENT and event.ui_element == self.input: if event.user_type == pygame_gui.UI_TEXT_ENTRY_FINISHED: self.speak(self.input.get_text())
class EverythingWindow(UIWindow): def __init__(self, rect, ui_manager): super().__init__(rect, ui_manager, window_display_title='Everything Container', object_id='#everything_window', resizable=True) self.test_slider = UIHorizontalSlider(pygame.Rect( (int(self.rect.width / 2), int(self.rect.height * 0.70)), (240, 25)), 50.0, (0.0, 100.0), self.ui_manager, container=self) self.slider_label = UILabel( pygame.Rect( (int(self.rect.width / 2) + 250, int(self.rect.height * 0.70)), (27, 25)), str(int(self.test_slider.get_current_value())), self.ui_manager, container=self) self.test_text_entry = UITextEntryLine(pygame.Rect( (int(self.rect.width / 2), int(self.rect.height * 0.50)), (200, -1)), self.ui_manager, container=self) self.test_text_entry.set_forbidden_characters('numbers') current_resolution_string = 'Item 1' self.test_drop_down_menu = UIDropDownMenu( [ 'Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7', 'Item 8', 'Item 9', 'Item 10', 'Item 11', 'Item 12', 'Item 13', 'Item 14', 'Item 15', 'Item 16', 'Item 17', 'Item 18', 'Item 19', 'Item 20', 'Item 21', 'Item 22', 'Item 23', 'Item 24', 'Item 25', 'Item 26', 'Item 27', 'Item 28', 'Item 29', 'Item 30' ], current_resolution_string, pygame.Rect( (int(self.rect.width / 2), int(self.rect.height * 0.3)), (200, 25)), self.ui_manager, container=self) self.health_bar = UIScreenSpaceHealthBar(pygame.Rect( (int(self.rect.width / 9), int(self.rect.height * 0.7)), (200, 20)), self.ui_manager, container=self) loaded_test_image = pygame.image.load( 'data/images/splat.png').convert_alpha() self.test_image = UIImage(pygame.Rect( (int(self.rect.width / 9), int(self.rect.height * 0.3)), loaded_test_image.get_rect().size), loaded_test_image, self.ui_manager, container=self) def update(self, time_delta): super().update(time_delta) if self.alive() and self.test_slider.has_moved_recently: self.slider_label.set_text( str(int(self.test_slider.get_current_value())))
class MapEditor: def __init__(self, tiled_level, hud_rect, all_square_sprites, ui_manager): self.editing_layer = 0 self.tiled_level = tiled_level self.hud_rect = hud_rect self.all_square_sprites = all_square_sprites self.ui_manager = ui_manager self.current_levels = [ file for file in os.listdir("data/levels/") if os.path.isfile(os.path.join("data/levels/", file)) ] self.left_mouse_held = False self.right_mouse_held = False self.need_to_refresh_tiles = True self.default_tile = [ pygame.Rect(0, 0, 0, 0), self.tiled_level.tile_map[0][0], "grass_tile", True, None ] self.held_tile_data = self.default_tile self.held_ai_spawn = None self.held_turret_square = None self.rect_of_tile = None self.hovered_rec = None self.rotate_selected_tile_left = False self.rotate_selected_tile_right = False self.all_palette_tile_sprites = pygame.sprite.Group() self.all_ai_spawn_sprites = pygame.sprite.Group() self.palette_page = 0 self.should_increase_palette_page = False self.should_decrease_palette_page = False self.remove_turret_square_icon = None self.place_turret_square_icon = None self.remove_waypoint_icon = None self.place_waypoint_icon = None self.right_click_mode = "place_tile" self.palette_tiles = [] self.palette_ai_spawns = [] self.num_ai_spawns = 3 self.tiles_per_page = 26 all_tiles_and_ai = len( self.tiled_level.all_tile_data.keys()) + self.num_ai_spawns self.max_pages = int(math.ceil(all_tiles_and_ai / self.tiles_per_page)) self.refresh_palette_tiles() self.left_scroll_held = False self.right_scroll_held = False self.up_scroll_held = False self.down_scroll_held = False self.map_scroll_speed = 256.0 self.map_start_pos = self.tiled_level.find_player_start() self.map_position = [self.map_start_pos[0], self.map_start_pos[1]] # self.map_editor_instructions = MapEditorInstructionsWindow([362, 100, 300, 250], fonts) instructions_message = ( "Arrow keys to scroll map <br>" "Left mouse click to select tile from palette<br>" "Right mouse click to place tile<br>" "'>' and '<' to rotate selected tile<br>" "F5 or quit to save map<br>") self.instruction_message_window = UIMessageWindow( pygame.Rect((362, 100), (300, 250)), "Instructions", instructions_message, self.ui_manager) self.level_name_label = UILabel(pygame.Rect((462, 8), (100, 34)), self.tiled_level.level_name, self.ui_manager, object_id="#screen_text") self.make_new_button = UIButton( pygame.Rect(870, self.hud_rect[1] + 24, 100, 20), "Make New", self.ui_manager) self.tile_set_button = UIButton( pygame.Rect(870, self.hud_rect[1] + 49, 100, 20), "Switch Tiles", self.ui_manager) self.playable_area_display = PlayableAreaDisplay() self.visible_way_point_circles = [] self.refresh_visible_waypoint_circles() def end(self): if self.tile_set_button is not None: self.tile_set_button.kill() self.tile_set_button = None if self.make_new_button is not None: self.make_new_button.kill() self.make_new_button = None if self.level_name_label is not None: self.level_name_label.kill() self.level_name_label = None if self.instruction_message_window is not None: self.instruction_message_window.kill() self.instruction_message_window = None for circle in self.visible_way_point_circles: circle.kill() def refresh_visible_waypoint_circles(self): for circle in self.visible_way_point_circles: circle.kill() del circle self.visible_way_point_circles[:] = [] traversal_order = 1 if self.tiled_level.monster_walk_path.start_waypoint is not None: self.visible_way_point_circles.append( DrawableWaypointCircle( self.tiled_level.monster_walk_path.waypoint_radius, self.tiled_level.monster_walk_path.start_waypoint, self.ui_manager, traversal_order)) traversal_order += 1 for waypoint in self.tiled_level.monster_walk_path.waypoints: self.visible_way_point_circles.append( DrawableWaypointCircle( self.tiled_level.monster_walk_path.waypoint_radius, waypoint, self.ui_manager, traversal_order)) traversal_order += 1 def display_turret_placement_squares(self, screen): self.all_square_sprites.draw(screen) def increase_palette_pos(self, x_pos, y_pos): x_pos += self.tiled_level.tile_size[0] + 8 if x_pos > 800: x_pos = 40 y_pos += self.tiled_level.tile_size[1] + 8 return x_pos, y_pos def refresh_palette_tiles(self): self.all_palette_tile_sprites.empty() self.palette_tiles[:] = [] self.palette_ai_spawns[:] = [] x_pos = 40 y_pos = 40 sorted_tile_keys = sorted(self.tiled_level.all_tile_data.keys()) display_tile = self.palette_page * self.tiles_per_page max_tile = (self.palette_page * self.tiles_per_page) + self.tiles_per_page min_tile = len(sorted_tile_keys) + self.num_ai_spawns while display_tile < min_tile and display_tile < max_tile: if display_tile < len(sorted_tile_keys): tile_data = sorted_tile_keys[display_tile] self.palette_tiles.append( Tile([self.hud_rect[0] + x_pos, self.hud_rect[1] + y_pos], 0, self.tiled_level.all_tile_data[tile_data], self.editing_layer)) display_tile += 1 else: self.remove_turret_square_icon = RemoveTurretSquareIcon( [self.hud_rect[0] + x_pos, self.hud_rect[1] + y_pos], self.all_palette_tile_sprites) x_pos, y_pos = self.increase_palette_pos(x_pos, y_pos) display_tile += 1 self.place_turret_square_icon = PlaceTurretSquareIcon( [self.hud_rect[0] + x_pos, self.hud_rect[1] + y_pos], self.all_palette_tile_sprites) x_pos, y_pos = self.increase_palette_pos(x_pos, y_pos) display_tile += 1 self.remove_waypoint_icon = RemoveWaypointIcon( [self.hud_rect[0] + x_pos, self.hud_rect[1] + y_pos], self.all_palette_tile_sprites) x_pos, y_pos = self.increase_palette_pos(x_pos, y_pos) display_tile += 1 self.place_waypoint_icon = PlaceWaypointIcon( [self.hud_rect[0] + x_pos, self.hud_rect[1] + y_pos], self.all_palette_tile_sprites) x_pos, y_pos = self.increase_palette_pos(x_pos, y_pos) display_tile += 1 display_tile += self.num_ai_spawns x_pos, y_pos = self.increase_palette_pos(x_pos, y_pos) for tile in self.palette_tiles: self.all_palette_tile_sprites.add(tile) # for aiSpawn in self.paletteAISpawns: # self.allPaletteTileSprites.add(aiSpawn.sprite) def run(self, screen, background, all_tile_sprites, hud_rect, time_delta): running = True for event in pygame.event.get(): self.ui_manager.process_events(event) if event.type == USEREVENT: if event.user_type == "ui_button_pressed": if event.ui_element == self.make_new_button: new_level_num = len(self.current_levels) + 1 new_level_name = "Level " + str(new_level_num) self.tiled_level.change_level_name_and_save( new_level_name) self.level_name_label.set_text( self.tiled_level.level_name) elif event.ui_element == self.tile_set_button: self.tiled_level.toggle_tile_map() for tile in self.palette_tiles: tile.reload_tile_image_from_data( self.tiled_level.all_tile_data) if event.type == QUIT: self.tiled_level.save_tiles() running = False if event.type == MOUSEBUTTONDOWN: if event.button == 1: self.left_mouse_held = True if event.button == 3: self.right_mouse_held = True if event.type == MOUSEBUTTONUP: if event.button == 1: self.left_mouse_held = False if event.button == 3: self.right_mouse_held = False if event.type == KEYDOWN: if event.key == K_ESCAPE: self.tiled_level.save_tiles() running = False if event.key == K_F5: self.tiled_level.save_tiles() if event.key == K_PERIOD: self.rotate_selected_tile_right = True if event.key == K_COMMA: self.rotate_selected_tile_left = True if event.key == K_UP: self.up_scroll_held = True if event.key == K_DOWN: self.down_scroll_held = True if event.key == K_LEFT: self.left_scroll_held = True if event.key == K_RIGHT: self.right_scroll_held = True if event.key == K_1: self.editing_layer = 1 if event.key == K_0: self.editing_layer = 0 if event.key == K_RIGHTBRACKET: self.should_increase_palette_page = True if event.key == K_LEFTBRACKET: self.should_decrease_palette_page = True if event.type == KEYUP: if event.key == K_UP: self.up_scroll_held = False if event.key == K_DOWN: self.down_scroll_held = False if event.key == K_LEFT: self.left_scroll_held = False if event.key == K_RIGHT: self.right_scroll_held = False self.ui_manager.update(time_delta) if self.should_increase_palette_page: self.should_increase_palette_page = False if self.palette_page < self.max_pages - 1: self.palette_page += 1 else: self.palette_page = 0 # loop back round self.refresh_palette_tiles() if self.should_decrease_palette_page: self.should_decrease_palette_page = False if self.palette_page > 0: self.palette_page -= 1 else: self.palette_page = self.max_pages - 1 # loop back round self.refresh_palette_tiles() if self.up_scroll_held: self.map_position[1] -= self.map_scroll_speed * time_delta if self.map_position[1] < self.tiled_level.initial_screen_offset[1]: self.map_position[1] = self.tiled_level.initial_screen_offset[ 1] if self.down_scroll_held: self.map_position[1] += self.map_scroll_speed * time_delta y_limit = self.tiled_level.level_pixel_size[ 1] - self.tiled_level.initial_screen_offset[1] + self.hud_rect[ 1] if self.map_position[1] > y_limit: self.map_position[1] = y_limit if self.left_scroll_held: self.map_position[0] -= self.map_scroll_speed * time_delta if self.map_position[0] < self.tiled_level.initial_screen_offset[0]: self.map_position[0] = self.tiled_level.initial_screen_offset[ 0] if self.right_scroll_held: self.map_position[0] += self.map_scroll_speed * time_delta max_x = self.tiled_level.level_pixel_size[ 0] - self.tiled_level.initial_screen_offset[0] if self.map_position[0] > max_x: self.map_position[0] = max_x if self.rotate_selected_tile_right and self.held_tile_data[ 4] is not None: self.rotate_selected_tile_right = False self.held_tile_data[4].rotate_tile_right() self.need_to_refresh_tiles = True if self.rotate_selected_tile_left and self.held_tile_data[ 4] is not None: self.rotate_selected_tile_left = False self.held_tile_data[4].rotate_tile_left() self.need_to_refresh_tiles = True if self.left_mouse_held: click_pos = pygame.mouse.get_pos() if self.is_inside_hud(click_pos, hud_rect): self.held_tile_data = self.get_palette_tile_data_at_pos( click_pos) if self.held_tile_data is None: if self.remove_turret_square_icon.is_inside(click_pos): self.right_click_mode = "remove_turret_square" elif self.place_turret_square_icon.is_inside(click_pos): self.right_click_mode = "place_turret_square" elif self.remove_waypoint_icon.is_inside(click_pos): self.right_click_mode = "remove_waypoint" elif self.place_waypoint_icon.is_inside(click_pos): self.right_click_mode = "place_waypoint" else: self.right_click_mode = "place_tile" else: self.held_tile_data = self.tiled_level.get_tile_data_at_pos( click_pos, self.editing_layer) if self.right_mouse_held: click_pos = pygame.mouse.get_pos() if self.is_inside_hud(click_pos, hud_rect): pass else: angle = 0 if self.right_click_mode == "place_tile" and self.held_tile_data is not None: if self.held_tile_data[4] is not None: angle = self.held_tile_data[4].angle self.rect_of_tile = self.tiled_level.set_tile_at_pos( click_pos, self.held_tile_data[2], angle, self.editing_layer) elif self.right_click_mode == "place_ai" and self.held_ai_spawn is not None: self.tiled_level.add_ai_spawn_at_pos( click_pos, self.held_ai_spawn) elif self.right_click_mode == "remove_ai": self.tiled_level.remove_ai_spawn_at_pos(click_pos) elif self.right_click_mode == "remove_turret_square": self.tiled_level.remove_turret_square_at_pos(click_pos) elif self.right_click_mode == "place_turret_square": self.tiled_level.place_turret_square_at_pos(click_pos) elif self.right_click_mode == "remove_waypoint": self.tiled_level.remove_waypoint_at_pos(click_pos) self.refresh_visible_waypoint_circles() elif self.right_click_mode == "place_waypoint": if self.tiled_level.place_waypoint_at_pos(click_pos): self.refresh_visible_waypoint_circles() if self.tiled_level.update_offset_position(self.map_position, all_tile_sprites): self.need_to_refresh_tiles = True self.all_ai_spawn_sprites.empty() for ai_spawn in self.tiled_level.ai_spawns: self.all_ai_spawn_sprites.add(ai_spawn) self.hovered_rec = self.tiled_level.get_tile_data_at_pos( pygame.mouse.get_pos(), self.editing_layer)[0] screen.blit(background, (0, 0)) # draw the background all_tile_sprites.draw(screen) self.all_ai_spawn_sprites.draw(screen) self.playable_area_display.draw(screen, self.tiled_level.position_offset) self.display_turret_placement_squares(screen) for waypoint_circles in self.visible_way_point_circles: waypoint_circles.update_offset_position( self.tiled_level.position_offset) waypoint_circles.draw(screen) if self.held_tile_data is not None: if not self.held_tile_data[3]: pygame.draw.rect(screen, pygame.Color("#FF6464"), self.held_tile_data[0], 1) if self.hovered_rec is not None: pygame.draw.rect(screen, pygame.Color("#FFE164"), self.hovered_rec, 1) # draw the hud pygame.draw.rect(screen, pygame.Color("#3C3C3C"), hud_rect, 0) self.all_palette_tile_sprites.draw(screen) if self.held_tile_data is not None: if self.held_tile_data[3]: pygame.draw.rect(screen, pygame.Color("#FF6464"), self.held_tile_data[0], 1) self.ui_manager.draw_ui(screen) return running @staticmethod def is_inside_hud(pos, hud_rect): if hud_rect[0] <= pos[0] and hud_rect[1] <= pos[1]: if hud_rect[0] + hud_rect[2] > pos[ 0] and hud_rect[1] + hud_rect[3] > pos[1]: return True return False def get_palette_tile_data_at_pos(self, click_pos): for tile in self.palette_tiles: x_min = tile.rect[0] x_max = tile.rect[0] + tile.rect[2] y_min = tile.rect[1] y_max = tile.rect[1] + tile.rect[3] if x_min <= click_pos[0] < x_max: if y_min <= click_pos[1] < y_max: return [tile.rect, tile.image, tile.tile_id, True, None] return None def get_ai_spawn_data_at_pos(self, click_pos): for ai_spawn in self.palette_ai_spawns: x_min = ai_spawn.rect[0] x_max = ai_spawn.rect[0] + ai_spawn.rect[2] y_min = ai_spawn.rect[1] y_max = ai_spawn.rect[1] + ai_spawn.rect[3] if x_min <= click_pos[0] < x_max: if y_min <= click_pos[1] < y_max: return ai_spawn return None
class OptionsUIApp: def __init__(self): pygame.init() pygame.display.set_caption("Options UI") self.options = Options() if self.options.fullscreen: self.window_surface = pygame.display.set_mode( self.options.resolution, pygame.FULLSCREEN) else: self.window_surface = pygame.display.set_mode( self.options.resolution) self.background_surface = None self.ui_manager = UIManager( self.options.resolution, PackageResource(package='data.themes', resource='theme_2.json')) self.ui_manager.preload_fonts([{ 'name': 'fira_code', 'point_size': 10, 'style': 'bold' }, { 'name': 'fira_code', 'point_size': 10, 'style': 'regular' }, { 'name': 'fira_code', 'point_size': 10, 'style': 'italic' }, { 'name': 'fira_code', 'point_size': 14, 'style': 'italic' }, { 'name': 'fira_code', 'point_size': 14, 'style': 'bold' }]) self.test_button = None self.test_button_2 = None self.test_button_3 = None self.test_slider = None self.test_text_entry = None self.test_drop_down = None self.test_drop_down_2 = None self.panel = None self.fps_counter = None self.frame_timer = None self.disable_toggle = None self.hide_toggle = None self.message_window = None self.recreate_ui() self.clock = pygame.time.Clock() self.time_delta_stack = deque([]) self.button_response_timer = pygame.time.Clock() self.running = True self.debug_mode = False self.all_enabled = True self.all_shown = True def recreate_ui(self): self.ui_manager.set_window_resolution(self.options.resolution) self.ui_manager.clear_and_reset() self.background_surface = pygame.Surface(self.options.resolution) self.background_surface.fill( self.ui_manager.get_theme().get_colour('dark_bg')) self.test_button = UIButton( pygame.Rect((int(self.options.resolution[0] / 2), int(self.options.resolution[1] * 0.90)), (100, 40)), '', self.ui_manager, tool_tip_text="<font face=fira_code color=normal_text size=2>" "<b><u>Test Tool Tip</u></b>" "<br><br>" "A little <i>test</i> of the " "<font color=#FFFFFF><b>tool tip</b></font>" " functionality." "<br><br>" "Unleash the Kraken!" "</font>", object_id='#hover_me_button') self.test_button_2 = UIButton(pygame.Rect( (int(self.options.resolution[0] / 3), int(self.options.resolution[1] * 0.90)), (100, 40)), 'EVERYTHING', self.ui_manager, object_id='#everything_button') self.test_button_3 = UIButton(pygame.Rect( (int(self.options.resolution[0] / 6), int(self.options.resolution[1] * 0.90)), (100, 40)), 'Scaling?', self.ui_manager, object_id='#scaling_button') self.test_slider = UIHorizontalSlider(pygame.Rect( (int(self.options.resolution[0] / 2), int(self.options.resolution[1] * 0.70)), (240, 25)), 25.0, (0.0, 100.0), self.ui_manager, object_id='#cool_slider') self.test_text_entry = UITextEntryLine(pygame.Rect( (int(self.options.resolution[0] / 2), int(self.options.resolution[1] * 0.50)), (200, -1)), self.ui_manager, object_id='#main_text_entry') current_resolution_string = (str(self.options.resolution[0]) + 'x' + str(self.options.resolution[1])) self.test_drop_down = UIDropDownMenu( ['640x480', '800x600', '1024x768'], current_resolution_string, pygame.Rect((int(self.options.resolution[0] / 2), int(self.options.resolution[1] * 0.3)), (200, 25)), self.ui_manager) self.test_drop_down_2 = UIDropDownMenu( ['Another', 'drop down', 'menu', 'testing', 'overlaps'], 'Another', pygame.Rect((int(self.options.resolution[0] / 2), int(self.options.resolution[1] * 0.25)), (200, 25)), self.ui_manager) self.panel = UIPanel(pygame.Rect(50, 50, 200, 300), starting_layer_height=4, manager=self.ui_manager) UIButton(pygame.Rect(10, 10, 174, 30), 'Panel Button', manager=self.ui_manager, container=self.panel) UISelectionList(pygame.Rect(10, 50, 174, 200), item_list=[ 'Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7', 'Item 8', 'Item 9', 'Item 10', 'Item 11', 'Item 12', 'Item 13', 'Item 14', 'Item 15', 'Item 16', 'Item 17', 'Item 18', 'Item 19', 'Item 20' ], manager=self.ui_manager, container=self.panel, allow_multi_select=True) self.fps_counter = UILabel(pygame.Rect( self.options.resolution[0] - 250, 20, 230, 44), "FPS: 0", self.ui_manager, object_id='#fps_counter') self.frame_timer = UILabel(pygame.Rect( self.options.resolution[0] - 250, 64, 230, 24), "Frame time: 0", self.ui_manager, object_id='#frame_timer') self.disable_toggle = UIButton(pygame.Rect( (int(self.options.resolution[0] * 0.85), int(self.options.resolution[1] * 0.90)), (100, 30)), 'Disable', self.ui_manager, object_id='#disable_button') self.hide_toggle = UIButton(pygame.Rect( (int(self.options.resolution[0] * 0.85), int(self.options.resolution[1] * 0.85)), (100, 30)), 'Hide', self.ui_manager, object_id='#hide_button') def create_message_window(self): self.button_response_timer.tick() self.message_window = UIMessageWindow( rect=pygame.Rect( (random.randint(0, self.options.resolution[0] - 300), random.randint(0, self.options.resolution[1] - 200)), (300, 250)), window_title='Test Message Window', html_message='<font color=normal_text>' 'This is a <a href="test">test</a> message to see if ' 'this box <a href=actually_link>actually</a> works.' '' 'In <i>bibendum</i> orci et velit</b> gravida lacinia.<br><br><br> ' 'In hac a habitasse to platea dictumst.<br>' ' <font color=#4CD656 size=4>Vivamus I interdum mollis lacus nec ' 'porttitor.<br> Morbi' ' accumsan, lectus at' ' tincidunt to dictum, neque <font color=#879AF6>erat tristique' ' blob</font>,' ' sed a tempus for <b>nunc</b> dolor in nibh.<br>' ' Suspendisse in viverra dui <i>fringilla dolor laoreet</i>, sit amet ' 'on pharetra a ante' ' sollicitudin.</font>' '<br><br>' 'In <i>bibendum</i> orci et velit</b> gravida lacinia.<br><br><br> ' 'In hac a habitasse to platea dictumst.<br>' ' <font color=#4CD656 size=4>Vivamus I interdum mollis lacus nec ' 'porttitor.<br> Morbi' ' accumsan, lectus at' ' tincidunt to dictum, neque <font color=#879AF6>erat tristique ' 'erat</font>,' ' sed a tempus for <b>nunc</b> dolor in nibh.<br>' ' Suspendisse in viverra dui <i>fringilla dolor laoreet</i>, sit amet ' 'on pharetra a ante' ' sollicitudin.</font>' '<br><br>' 'In <i>bibendum</i> orci et velit</b> gravida lacinia.<br><br><br> ' 'In hac a habitasse to platea dictumst.<br>' ' <font color=#4CD656 size=4>Vivamus I interdum mollis lacus nec ' 'porttitor.<br> Morbi' ' accumsan, lectus at' ' tincidunt to dictum, neque <font color=#879AF6>erat tristique ' 'erat</font>,' ' sed a tempus for <b>nunc</b> dolor in nibh.<br>' ' Suspendisse in viverra dui <i>fringilla dolor laoreet</i>, ' 'sit amet on pharetra a ante' ' sollicitudin.</font>' '</font>', manager=self.ui_manager) time_taken = self.button_response_timer.tick() / 1000.0 # currently taking about 0.35 seconds down from 0.55 to create # an elaborately themed message window. # still feels a little slow but it's better than it was. print("Time taken to create message window: " + str(time_taken)) def check_resolution_changed(self): resolution_string = self.test_drop_down.selected_option.split('x') resolution_width = int(resolution_string[0]) resolution_height = int(resolution_string[1]) if (resolution_width != self.options.resolution[0] or resolution_height != self.options.resolution[1]): self.options.resolution = (resolution_width, resolution_height) self.window_surface = pygame.display.set_mode( self.options.resolution) self.recreate_ui() def process_events(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False self.ui_manager.process_events(event) if event.type == pygame.KEYDOWN and event.key == pygame.K_d: self.debug_mode = False if self.debug_mode else True self.ui_manager.set_visual_debug_mode(self.debug_mode) if event.type == pygame.KEYDOWN and event.key == pygame.K_f: print("self.ui_manager.focused_set:", self.ui_manager.focused_set) if event.type == pygame.USEREVENT: if (event.user_type == pygame_gui.UI_TEXT_ENTRY_FINISHED and event.ui_object_id == '#main_text_entry'): print(event.text) if event.user_type == pygame_gui.UI_TEXT_BOX_LINK_CLICKED: if event.link_target == 'test': print("clicked test link") elif event.link_target == 'actually_link': print("clicked actually link") if event.user_type == pygame_gui.UI_BUTTON_PRESSED: if event.ui_element == self.test_button: self.test_button.set_text( random.choice( ['', 'Hover me!', 'Click this.', 'A Button'])) self.create_message_window() if event.ui_element == self.test_button_3: ScalingWindow(pygame.Rect((50, 50), (224, 224)), self.ui_manager) if event.ui_element == self.test_button_2: EverythingWindow(pygame.Rect((10, 10), (640, 480)), self.ui_manager) if event.ui_element == self.disable_toggle: if self.all_enabled: self.disable_toggle.set_text('Enable') self.all_enabled = False self.ui_manager.root_container.disable() self.disable_toggle.enable() else: self.disable_toggle.set_text('Disable') self.all_enabled = True self.ui_manager.root_container.enable() if event.ui_element == self.hide_toggle: if self.all_shown: self.hide_toggle.set_text('Show') self.all_shown = False self.ui_manager.root_container.hide() self.hide_toggle.show() else: self.hide_toggle.set_text('Hide') self.all_shown = True self.ui_manager.root_container.show() if (event.user_type == pygame_gui.UI_DROP_DOWN_MENU_CHANGED and event.ui_element == self.test_drop_down): self.check_resolution_changed() def run(self): while self.running: time_delta = self.clock.tick() / 1000.0 self.time_delta_stack.append(time_delta) if len(self.time_delta_stack) > 2000: self.time_delta_stack.popleft() # check for input self.process_events() # respond to input self.ui_manager.update(time_delta) if len(self.time_delta_stack) == 2000: self.fps_counter.set_text( f'FPS: {min(999.0, 1.0/max(sum(self.time_delta_stack)/2000.0, 0.0000001)):.2f}' ) self.frame_timer.set_text( f'frame_time: {sum(self.time_delta_stack)/2000.0:.4f}') # draw graphics self.window_surface.blit(self.background_surface, (0, 0)) self.ui_manager.draw_ui(self.window_surface) pygame.display.update()
class Game: def __init__(self, session): self.manager = UIManager((800, 600), 'themes/game.json') image = pygame.image.load('assets/background.png') self.background = UIImage(relative_rect=pygame.Rect(0, 0, 800, 600), manager=self.manager, image_surface=image) self.session = session self.allPlayers = pygame.sprite.Group() self.player = Perso(self, self.session) self.allPlayers.add(self.player) self.pressed = {} self.allEnemy = pygame.sprite.Group() self.addScore = 100 self.score = 0 self.level = Niveau(self, self.score) self.panelTop = UIPanel(relative_rect=pygame.Rect(0, 0, 800, 20), starting_layer_height=2, manager=self.manager, object_id="#panel-top") self.labelHealthTitle = UILabel(relative_rect=pygame.Rect( 0, 0, 50, 20), text="Vie :", manager=self.manager, object_id="#label-score", container=self.panelTop) self.labelHealth = UILabel(relative_rect=pygame.Rect(30, 0, 50, 20), text=str(self.player.health), manager=self.manager, object_id="#label-score", container=self.panelTop) self.labelAsset = UILabel(relative_rect=pygame.Rect( 800 - 100, 0, 50, 20), text=str(self.level.assetIsActive[2]), manager=self.manager, object_id="#label-score", container=self.panelTop) self.labelScore = UILabel(relative_rect=pygame.Rect( 0, 600 - 50, 200, 50), text=str(self.score), manager=self.manager, object_id="#label-score") self.playerImage = UIImage(relative_rect=pygame.Rect( (self.player.rect.x, self.player.rect.y), (50, 50)), manager=self.manager, image_surface=self.player.image) self.panel = UIPanel(relative_rect=pygame.Rect((0, 0), (0, 0)), starting_layer_height=3, manager=self.manager, object_id="#panel-game-over") self.labelGameOver = UILabel(relative_rect=pygame.Rect( 400 - 100, 300 - 50, 200, 50), text="Game Over", manager=self.manager, object_id="#label-game-over", container=self.panel) self.buttonMenu = UIButton(relative_rect=pygame.Rect( 400 - 100, 300 + 50, 200, 50), text='Quitter', manager=self.manager, container=self.panel) self.buttonParty = UIButton(relative_rect=pygame.Rect( (400 - 100, 300 + 50 + 80), (200, 50)), text='Recommencer', manager=self.manager, container=self.panel) self.panelPause = UIPanel(relative_rect=pygame.Rect((0, 0), (0, 0)), starting_layer_height=3, manager=self.manager, object_id="#panel-game-over") self.labelPause = UILabel(relative_rect=pygame.Rect( 400 - 100, 300 - 50, 200, 50), text="Pause", manager=self.manager, object_id="#label-game-over", container=self.panelPause) self.buttonSave = UIButton(relative_rect=pygame.Rect( 400 - 100, 300 + 50, 200, 50), text='Sauvegarder et quitter', manager=self.manager, container=self.panelPause) self.buttonQuit = UIButton(relative_rect=pygame.Rect( (400 - 100, 300 + 50 + 80), (200, 50)), text='Quitter', manager=self.manager, container=self.panelPause) self.panelAsset = UIPanel(relative_rect=pygame.Rect((0, 0), (0, 0)), starting_layer_height=3, manager=self.manager, object_id="#panel-game-over") self.labelEquipment = UILabel(relative_rect=pygame.Rect( 400 - 100, 50, 200, 50), text="Pause", manager=self.manager, object_id="#label-game-over", container=self.panelAsset) self.button1 = UIButton(relative_rect=pygame.Rect( 400 - 100, 50 + 50, 200, 50), text="Double l'attaque 10C", manager=self.manager, container=self.panelAsset) self.button2 = UIButton(relative_rect=pygame.Rect( (400 - 100, 120 + 50), (200, 50)), text='3 Missiles 100C', manager=self.manager, container=self.panelAsset) self.button3 = UIButton(relative_rect=pygame.Rect( (400 - 100, 190 + 50), (200, 50)), text='Double Score 20C', manager=self.manager, container=self.panelAsset) self.button4 = UIButton(relative_rect=pygame.Rect( (400 - 100, 260 + 50), (200, 50)), text="Temps d'apparition 50C", manager=self.manager, container=self.panelAsset) self.labelCredit = UILabel(relative_rect=pygame.Rect( 400 - 100, 330 + 50, 200, 50), text=str(self.player.credit), manager=self.manager, object_id="#label-game-over", container=self.panelAsset) self.pause = True def menuGameOver(self): self.panel.set_dimensions((800, 600)) def setLabelHealth(self): self.labelHealth.set_text(str(self.player.health)) def setLabelScore(self): self.labelScore.set_text(str(self.score)) def setLabelAsset(self): self.labelAsset.set_text(str(self.level.assetIsActive[2])) def setLabelCredit(self): self.player.credit += 1 self.labelCredit.set_text(str(self.player.credit)) def getManager(self): return self.manager def updatePosPlayer(self): self.playerImage.set_relative_position( (self.player.rect.x, self.player.rect.y)) def getPause(self): return self.pause def getEvent(self, event): if not self.player.isDead(): if event.type == pygame.USEREVENT: if event.user_type == pygame_gui.UI_BUTTON_PRESSED: if event.ui_element == self.buttonQuit: pygame.quit() elif event.ui_element == self.buttonSave: self.session.setCredit(self.player.credit) self.session.setScore(self.score) pygame.quit() elif event.ui_element == self.button1: if self.player.credit >= 10 and self.level.assetIsActive[ 0] == False: self.player.credit -= 10 self.player.getSurprise("damage") self.panelAsset.set_dimensions((0, 0)) self.pause = True elif event.ui_element == self.button2: if self.player.credit >= 100 and self.level.assetIsActive[ 0] == False: self.player.credit -= 100 self.player.getSurprise("attack") self.panelAsset.set_dimensions((0, 0)) self.pause = True elif event.ui_element == self.button3: if self.player.credit >= 20 and self.level.assetIsActive[ 0] == False: self.player.credit -= 20 self.player.getSurprise("score") self.panelAsset.set_dimensions((0, 0)) self.pause = True elif event.ui_element == self.button4: if self.player.credit >= 50 and self.level.assetIsActive[ 0] == False: self.player.credit -= 50 self.player.getSurprise("reload") self.panelAsset.set_dimensions((0, 0)) self.pause = True if event.type == KEYDOWN: if event.key == pygame.K_ESCAPE: if self.pause: self.panelPause.set_dimensions((800, 600)) self.pause = False else: self.panelPause.set_dimensions((0, 0)) self.pause = True return self.pause if event.key == pygame.K_RETURN: if self.pause: self.panelAsset.set_dimensions((800, 600)) self.pause = False else: self.panelAsset.set_dimensions((0, 0)) self.pause = True return self.pause if event.key == pygame.K_SPACE: self.player.attack(self.manager) self.pressed[event.key] = True elif event.type == KEYUP: self.pressed[event.key] = False return None else: if event.type == pygame.USEREVENT: if event.user_type == pygame_gui.UI_BUTTON_PRESSED: if event.ui_element == self.buttonParty: return "restart" elif event.ui_element == self.buttonMenu: pygame.quit() def updatePosEnemy(self, enemy, x, y): enemy.ennemyImage.set_relative_position((x, y)) def spawnEnemy(self, health, x, asset): enemy = Enemy(health, self.manager, x, self, asset) self.updatePosEnemy(enemy, enemy.rect.x, enemy.rect.y) self.allEnemy.add(enemy) def checkColision(self, sprite, group): return pygame.sprite.spritecollide(sprite, group, False, pygame.sprite.collide_mask) def run(self): self.level.generate() self.level.setScore(self.score)
class HUDPanel(UIWindow): def __init__(self, rect: pygame.Rect, manager: 'pygame_gui.ui_manager.UIManager', player_resources: PlayerResources, turret_costs: TurretCosts): super().__init__(rect, manager, 'hud_panel') self.player_resources = player_resources self.turret_costs = turret_costs # create top edge shadow top_edge_shadow_size = 4 border_size = 1 background_surface = pygame.Surface( (self.rect.width, self.rect.height - top_edge_shadow_size)) background_surface.fill(pygame.Color("#808080")) background_surface.fill( pygame.Color("#646464"), pygame.Rect( (border_size, border_size), (self.rect.width - (border_size * 2), self.rect.height - (border_size * 2) - top_edge_shadow_size))) shadow = self.ui_manager.get_shadow( (self.rect.width + 48, self.rect.height)) self.image = pygame.Surface(self.rect.size, flags=pygame.SRCALPHA) self.image.blit(shadow, (0, 0), area=pygame.Rect((24, 0), self.rect.size)) self.image.blit(background_surface, (0, top_edge_shadow_size)) self.get_container().relative_rect.width = self.rect.width self.get_container( ).relative_rect.height = self.rect.height - top_edge_shadow_size self.get_container().relative_rect.x = self.get_container( ).relative_rect.x self.get_container().relative_rect.y = self.get_container( ).relative_rect.y + top_edge_shadow_size self.get_container().update_containing_rect_position() self.health_label = UILabel( pygame.Rect((900, 30), (100, 40)), "Health: " + "{:,}".format(self.player_resources.current_base_health), manager=self.ui_manager, container=self.get_container(), object_id="#screen_text") self.cash_label = UILabel( pygame.Rect((900, 60), (100, 40)), "£" + "{:,}".format(self.player_resources.current_cash), manager=self.ui_manager, container=self.get_container(), object_id="#screen_text") self.clearable_hud_elements = [] def update(self, time_delta: float): self.cash_label.set_text( "£" + "{:,}".format(self.player_resources.current_cash)) self.health_label.set_text( "Health: " + "{:,}".format(self.player_resources.current_base_health)) def display_normal_hud(self): for element in self.clearable_hud_elements: element.kill() self.clearable_hud_elements.clear() self.clearable_hud_elements.append( UIButton( pygame.Rect(32, 32, 66, 66), "", manager=self.ui_manager, container=self.get_container(), object_id="#gun_turret_button", tool_tip_text="<font size=2><b>Gun Turret</b><br><br>" "A turret that fires a pair of low damage bullets at enemies in range. Has a" " fairly rapid rate of fire.</font>")) self.clearable_hud_elements.append( UIButton( pygame.Rect(128, 32, 66, 66), "", manager=self.ui_manager, container=self.get_container(), object_id="#missile_turret_button", tool_tip_text="<font size=2><b>Missile Turret</b><br><br>" "A slow firing, large range turret that launches homing missiles. Missiles do high " "damage.</font>")) self.clearable_hud_elements.append( UIButton( pygame.Rect(224, 32, 66, 66), "", manager=self.ui_manager, container=self.get_container(), object_id="#flame_turret_button", tool_tip_text="<font size=2><b>Flame Turret</b><br><br>" "Short range turret that fires a continuous cone of flame." " The flames do damage while an enemy is within the cone. " "Works well when enemies have to walk directly at the " "turret.</font>")) self.clearable_hud_elements.append( UIButton( pygame.Rect(320, 32, 66, 66), "", manager=self.ui_manager, container=self.get_container(), object_id="#slow_turret_button", tool_tip_text="<font size=2><b>Slow Turret</b><br><br>" "This turret uses time warping fields to slow down" " all enemies within its radius. Works " "well to multiply the damage done by nearby turrets.</font>")) self.clearable_hud_elements.append( UIButton( pygame.Rect(416, 32, 66, 66), "", manager=self.ui_manager, container=self.get_container(), object_id="#laser_turret_button", tool_tip_text="<font size=2><b>Laser Turret</b><br><br>" "This turret fires a continuous laser beam at a single target." " Useful for dealing with armoured targets that resist other " "types of damage.</font>")) self.clearable_hud_elements.append( UILabel(pygame.Rect((32, 96), (64, 32)), "£ " + str(self.turret_costs.gun), manager=self.ui_manager, container=self.get_container(), object_id="#small_screen_text")) self.clearable_hud_elements.append( UILabel(pygame.Rect((128, 96), (64, 32)), "£ " + str(self.turret_costs.missile), manager=self.ui_manager, container=self.get_container(), object_id="#small_screen_text")) self.clearable_hud_elements.append( UILabel(pygame.Rect((224, 96), (64, 32)), "£ " + str(self.turret_costs.flamer), manager=self.ui_manager, container=self.get_container(), object_id="#small_screen_text")) self.clearable_hud_elements.append( UILabel(pygame.Rect((320, 96), (64, 32)), "£ " + str(self.turret_costs.slow), manager=self.ui_manager, container=self.get_container(), object_id="#small_screen_text")) self.clearable_hud_elements.append( UILabel(pygame.Rect((416, 96), (64, 32)), "£ " + str(self.turret_costs.laser), manager=self.ui_manager, container=self.get_container(), object_id="#small_screen_text")) def display_upgrade_hud(self, upgrade_turret): for element in self.clearable_hud_elements: element.kill() self.clearable_hud_elements.clear() self.clearable_hud_elements.append( UIButton(pygame.Rect(32, 32, 66, 66), "", manager=self.ui_manager, container=self.get_container(), object_id="#upgrade_button", tool_tip_text="<font size=2><b>Upgrade Turret</b><br><br>" "Upgrades the selected turret to the next level." " Turrets have three levels.</font>")) self.clearable_hud_elements.append( UIButton( pygame.Rect(128, 32, 66, 66), "", manager=self.ui_manager, container=self.get_container(), object_id="#sell_button", tool_tip_text="<font size=2><b>Sell Turret</b><br><br>" "Sells the selected turret for half of the cost of building it.</font>" )) self.clearable_hud_elements.append( UILabel(pygame.Rect((32, 96), (64, 32)), "£ " + str(upgrade_turret.get_upgrade_cost()), manager=self.ui_manager, container=self.get_container(), object_id="#small_screen_text")) self.clearable_hud_elements.append( UILabel(pygame.Rect((128, 96), (64, 32)), "£ " + str(upgrade_turret.get_sell_value()), manager=self.ui_manager, container=self.get_container(), object_id="#small_screen_text"))
class GameState(BaseAppState): def __init__(self, ui_manager: pygame_gui.UIManager, screen_surface, screen_data, state_manger): super().__init__('game', 'main_menu', state_manger) self.ui_manager = ui_manager self.screen_surface = screen_surface self.screen_data = screen_data self.background = None self.level_to_load_path = None self.level_to_load = None # objects that do stuff self.collision_grid = None self.tiled_level = None self.monster_wave_spawner = None self.splat_loader = None self.player_resources = None self.should_redraw_static_sprites = False # game sub state booleans self.is_play_game = False self.restart_game = False self.is_setup = False self.is_game_over = False self.should_show_count_down_message = False self.upgrade_hud_active = False self.hud_panel = None # labels self.fps_counter_label = None self.wave_display_label = None self.count_down_message_label = None self.health_label = None self.cash_label = None self.win_message_label = None self.play_again_message_label = None self.frame_rates = deque([]) # turrets self.active_upgrade_turret = None self.mouse_active_turret = None # lists of things self.explosions = [] self.new_explosions = [] self.bullets = [] self.turrets = [] self.monsters = [] self.hud_buttons = [] # sprite groups self.static_sprite_surface = None self.all_tile_sprites = None self.all_square_sprites = None self.all_monster_sprites = None self.all_turret_sprites = None self.all_bullet_sprites = None self.all_explosion_sprites = None self.splat_sprites = None # images self.explosions_sprite_sheet = None self.image_atlas = None self.turret_costs = TurretCosts() self.count_down_message = "" self.win_message = "" # timer self.setup_time = 10.0 self.setup_accumulator = 0.0 self.hud_rect = None def start(self): self.hud_rect = pygame.Rect(0, self.screen_data.screen_size[1] - 128, self.screen_data.screen_size[0], 128) self.player_resources = PlayerResources() self.background = pygame.Surface(self.screen_surface.get_size()) self.background = self.background.convert(self.screen_surface) self.background.fill((95, 140, 95)) self.should_redraw_static_sprites = True self.static_sprite_surface = pygame.Surface( self.screen_surface.get_size()) self.all_tile_sprites = pygame.sprite.Group() self.all_square_sprites = pygame.sprite.Group() self.all_monster_sprites = pygame.sprite.Group() self.all_turret_sprites = pygame.sprite.Group() self.all_bullet_sprites = pygame.sprite.Group() self.all_explosion_sprites = pygame.sprite.Group() self.splat_sprites = pygame.sprite.Group() self.explosions_sprite_sheet = pygame.image.load( "images/explosions.png").convert_alpha() self.image_atlas = pygame.image.load( "images/image_atlas.png").convert_alpha() self.splat_loader = SplatLoader() self.level_to_load_path = self.incoming_transition_data[ 'selected_level_path'] self.fps_counter_label = UILabel(pygame.Rect((900, 10), (100, 40)), "0 FPS", manager=self.ui_manager, object_id="#screen_text") self.wave_display_label = None grid_size = 64 screen_filling_number_of_grid_squares = [ int(self.screen_data.screen_size[0] / grid_size), int(self.screen_data.screen_size[1] / grid_size) ] self.collision_grid = CollisionGrid( screen_filling_number_of_grid_squares, grid_size) # clear level self.tiled_level = TiledLevel( self.level_to_load_path, [40, 21], self.all_tile_sprites, self.all_monster_sprites, self.all_square_sprites, self.image_atlas, self.monsters, self.screen_data, self.explosions_sprite_sheet) self.tiled_level.load_tiles() self.tiled_level.update_offset_position( self.tiled_level.find_player_start(), self.all_tile_sprites) self.monster_wave_spawner = MonsterWaveSpawner( self.monsters, self.tiled_level.monster_walk_path, 10, self.all_monster_sprites, self.image_atlas, self.collision_grid, self.splat_loader, self.ui_manager) self.is_play_game = True self.restart_game = True self.should_redraw_static_sprites = True self.hud_panel = HUDPanel(self.hud_rect, self.ui_manager, self.player_resources, self.turret_costs) def end(self): if self.fps_counter_label is not None: self.fps_counter_label.kill() self.fps_counter_label = None if self.count_down_message_label is not None: self.count_down_message_label.kill() self.count_down_message_label = None if self.wave_display_label is not None: self.wave_display_label.kill() self.wave_display_label = None if self.hud_panel is not None: self.hud_panel.kill() self.hud_panel = None if self.win_message_label is not None: self.win_message_label.kill() self.win_message_label = None if self.play_again_message_label is not None: self.play_again_message_label.kill() self.play_again_message_label = None for sprite in self.all_monster_sprites.sprites(): sprite.kill() self.all_monster_sprites.empty() self.all_turret_sprites.empty() self.all_bullet_sprites.empty() self.all_explosion_sprites.empty() def run(self, surface, time_delta): if not self.restart_game and self.is_setup: if self.setup_accumulator >= self.setup_time: self.is_setup = False self.setup_accumulator = 0.0 elif self.setup_accumulator >= (self.setup_time - 6.0): seconds_string = str( int(self.setup_time - self.setup_accumulator)) self.count_down_message = "First wave in " + seconds_string + " seconds" self.should_show_count_down_message = True self.setup_accumulator += time_delta if self.count_down_message_label is None: count_down_message_label_rect = pygame.Rect((400, 10), (250, 40)) count_down_message_label_rect.centerx = self.screen_data.screen_size[ 0] / 2 count_down_message_label_rect.centery = 24 self.count_down_message_label = UILabel( count_down_message_label_rect, self.count_down_message, manager=self.ui_manager, object_id="#screen_text") else: self.setup_accumulator += time_delta remaining_time = str( int(self.setup_time - self.setup_accumulator)) self.count_down_message = "Setup Time remaining: " + remaining_time + " seconds" self.should_show_count_down_message = True if self.count_down_message_label is None: count_down_message_label_rect = pygame.Rect((400, 10), (250, 40)) count_down_message_label_rect.centerx = self.screen_data.screen_size[ 0] / 2 count_down_message_label_rect.centery = 24 self.count_down_message_label = UILabel( count_down_message_label_rect, self.count_down_message, manager=self.ui_manager, object_id="#screen_text") elif self.restart_game: self.restart_game = False # clear all stuff self.explosions[:] = [] self.new_explosions[:] = [] self.bullets[:] = [] self.turrets[:] = [] self.monsters[:] = [] self.hud_buttons[:] = [] self.all_monster_sprites.empty() self.all_turret_sprites.empty() self.all_bullet_sprites.empty() self.all_explosion_sprites.empty() self.tiled_level.reset_squares() # reset player resources self.player_resources = PlayerResources() self.hud_panel.player_resources = self.player_resources self.is_game_over = False self.is_setup = True self.setup_accumulator = 0.0 self.monster_wave_spawner = MonsterWaveSpawner( self.monsters, self.tiled_level.monster_walk_path, 10, self.all_monster_sprites, self.image_atlas, self.collision_grid, self.splat_loader, self.ui_manager) self.mouse_active_turret = None self.active_upgrade_turret = None self.upgrade_hud_active = False self.should_show_count_down_message = False if self.count_down_message_label is not None: self.count_down_message_label.kill() self.count_down_message_label = None if self.wave_display_label is not None: self.wave_display_label.kill() self.wave_display_label = None if self.win_message_label is not None: self.win_message_label.kill() self.win_message_label = None if self.play_again_message_label is not None: self.play_again_message_label.kill() self.play_again_message_label = None self.hud_panel.display_normal_hud() elif self.is_game_over: self.should_show_count_down_message = False if self.count_down_message_label is not None: self.count_down_message_label.kill() self.count_down_message_label = None else: self.monster_wave_spawner.update(time_delta, self.tiled_level.position_offset) if self.wave_display_label is not None: self.wave_display_label.kill() self.wave_display_label = None if self.monster_wave_spawner.should_show_wave_countdown: self.should_show_count_down_message = True self.count_down_message = self.monster_wave_spawner.count_down_message if self.count_down_message_label is None: count_down_message_label_rect = pygame.Rect((400, 10), (250, 40)) count_down_message_label_rect.centerx = self.screen_data.screen_size[ 0] / 2 count_down_message_label_rect.centery = 24 self.count_down_message_label = UILabel( count_down_message_label_rect, self.count_down_message, manager=self.ui_manager, object_id="#screen_text") else: self.should_show_count_down_message = False if self.count_down_message_label is not None: self.count_down_message_label.kill() self.count_down_message_label = None if self.wave_display_label is None: current_wave = str( self.monster_wave_spawner.current_wave_number) max_wave = str( self.monster_wave_spawner.maximum_wave_number) wave_display_label_rect = pygame.Rect((400, 10), (100, 40)) wave_display_label_rect.centerx = self.screen_data.screen_size[ 0] / 2 wave_display_label_rect.centery = 24 self.wave_display_label = UILabel(wave_display_label_rect, "Wave " + current_wave + "/" + max_wave, manager=self.ui_manager, object_id="#screen_text") if not self.is_game_over and self.player_resources.current_base_health <= 0: self.is_game_over = True self.win_message = "You have been defeated!" self.win_message_label = UILabel(pygame.Rect((347, 200), (330, 70)), self.win_message, manager=self.ui_manager, object_id="#win_message_text") self.play_again_message_label = UILabel( pygame.Rect((362, 250), (300, 70)), "Play Again? Press 'Y' to restart", manager=self.ui_manager, object_id="#screen_text") on_final_wave = self.monster_wave_spawner.current_wave_number == self.monster_wave_spawner.maximum_wave_number if not self.is_game_over and on_final_wave and len(self.monsters) == 0: self.is_game_over = True self.win_message = "You are victorious!" self.win_message_label = UILabel(pygame.Rect((347, 200), (330, 70)), self.win_message, manager=self.ui_manager, object_id="#win_message_text") self.play_again_message_label = UILabel( pygame.Rect((362, 250), (300, 70)), "Play Again? Press 'Y' to restart", manager=self.ui_manager, object_id="#screen_text") self.all_turret_sprites.empty() self.all_bullet_sprites.empty() self.all_explosion_sprites.empty() # handle UI and inout events for event in pygame.event.get(): if event.type == pygame.QUIT: self.trigger_transition() if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.trigger_transition() if event.key == pygame.K_g: self.monster_wave_spawner.wave_points = 1000 self.monster_wave_spawner.wave_time_accumulator = 5.0 if event.key == pygame.K_y: if self.is_game_over: self.restart_game = True self.ui_manager.process_events(event) if event.type == pygame.USEREVENT: if event.user_type == "ui_button_pressed": if event.ui_object_id == "#gun_turret_button": if self.turret_costs.gun <= self.player_resources.current_cash: new_turret = GunTurret( pygame.mouse.get_pos(), self.turret_costs.gun, self.explosions_sprite_sheet, self.image_atlas, self.collision_grid) self.mouse_active_turret = new_turret self.turrets.append(new_turret) elif event.ui_object_id == "#flame_turret_button": if self.turret_costs.flamer <= self.player_resources.current_cash: new_turret = FlameTurret( pygame.mouse.get_pos(), self.turret_costs.flamer, self.explosions_sprite_sheet, self.image_atlas, self.collision_grid) self.mouse_active_turret = new_turret self.turrets.append(new_turret) elif event.ui_object_id == "#missile_turret_button": if self.turret_costs.missile <= self.player_resources.current_cash: new_turret = MissileTurret( pygame.mouse.get_pos(), self.turret_costs.missile, self.explosions_sprite_sheet, self.image_atlas, self.collision_grid) self.mouse_active_turret = new_turret self.turrets.append(new_turret) elif event.ui_object_id == "#slow_turret_button": if self.turret_costs.slow <= self.player_resources.current_cash: new_turret = SlowTurret(pygame.mouse.get_pos(), self.turret_costs.slow, self.image_atlas) self.mouse_active_turret = new_turret self.turrets.append(new_turret) elif event.ui_object_id == "#laser_turret_button": if self.turret_costs.laser <= self.player_resources.current_cash: new_turret = LaserTurret(pygame.mouse.get_pos(), self.turret_costs.laser, self.image_atlas) self.mouse_active_turret = new_turret self.turrets.append(new_turret) elif event.ui_object_id == "#upgrade_button": if self.active_upgrade_turret is not None: if self.player_resources.current_cash >= self.active_upgrade_turret.get_upgrade_cost( ): self.player_resources.current_cash -= self.active_upgrade_turret.get_upgrade_cost( ) self.active_upgrade_turret.upgrade() self.upgrade_hud_active = False self.active_upgrade_turret = None self.hud_panel.display_normal_hud() elif event.ui_object_id == "#sell_button": if self.active_upgrade_turret is not None: self.player_resources.current_cash += self.active_upgrade_turret.get_sell_value( ) for square in self.tiled_level.turret_squares: if square.rect.collidepoint( self.active_upgrade_turret.position): square.occupied = False self.turrets.remove(self.active_upgrade_turret) self.upgrade_hud_active = False self.active_upgrade_turret = None self.hud_panel.display_normal_hud() if not self.is_game_over and event.type == pygame.MOUSEBUTTONDOWN: if event.button == 3: if self.mouse_active_turret is not None: self.turrets[:] = [ turret for turret in self.turrets if turret is not self.mouse_active_turret ] self.mouse_active_turret = None if self.upgrade_hud_active: self.upgrade_hud_active = False self.hud_panel.display_normal_hud() if event.button == 1: if self.mouse_active_turret is not None: placed_turret = False for square in self.tiled_level.turret_squares: if self.mouse_active_turret is not None: if square.rect.collidepoint( pygame.mouse.get_pos( )) and not square.occupied: self.mouse_active_turret.set_position( square.position) placed_turret = True square.occupied = True self.player_resources.current_cash -= self.mouse_active_turret.build_cost self.mouse_active_turret.placed = True self.mouse_active_turret = None if not placed_turret: self.turrets[:] = [ turret for turret in self.turrets if turret is not self.mouse_active_turret ] self.mouse_active_turret = None else: for turret in self.turrets: if turret.rect.collidepoint( pygame.mouse.get_pos()): if turret.get_level() < turret.get_max_level(): self.upgrade_hud_active = True self.active_upgrade_turret = turret self.hud_panel.display_upgrade_hud( self.active_upgrade_turret) if not self.is_game_over and self.mouse_active_turret is not None: is_over_square = False for square in self.tiled_level.turret_squares: if square.rect.collidepoint( pygame.mouse.get_pos()) and not square.occupied: self.mouse_active_turret.set_position(square.position) self.mouse_active_turret.show_radius = True is_over_square = True if not is_over_square: self.mouse_active_turret.set_position(pygame.mouse.get_pos()) self.mouse_active_turret.show_radius = False for bullet in self.bullets: self.all_bullet_sprites = bullet.update_sprite( self.all_bullet_sprites) bullet.update_movement_and_collision(self.monsters, time_delta, self.new_explosions, self.explosions) self.bullets[:] = [ bullet for bullet in self.bullets if not bullet.should_die ] for monster in self.monsters: monster.update_movement_and_collision( time_delta, self.player_resources, self.tiled_level.position_offset, self.splat_sprites) monster.update_sprite() self.monsters[:] = [ monster for monster in self.monsters if not monster.should_die ] self.new_explosions[:] = [] for turret in self.turrets: turret.update_movement_and_collision(time_delta, self.monsters, self.bullets, pygame.mouse.get_pos()) self.all_turret_sprites = turret.update_sprite( self.all_turret_sprites) for explosion in self.explosions: self.all_explosion_sprites = explosion.update_sprite( self.all_explosion_sprites, time_delta) self.explosions[:] = [ explosion for explosion in self.explosions if not explosion.should_die ] self.splat_sprites.update(time_delta) self.collision_grid.update_shape_grid_positions() self.collision_grid.check_collisions() self.ui_manager.update(time_delta) for collided_shape in self.collision_grid.shapes_collided_this_frame: if collided_shape.owner is not None: collided_shape.owner.react_to_collision() if self.should_redraw_static_sprites: self.should_redraw_static_sprites = False self.static_sprite_surface.blit(self.background, (0, 0)) # draw the background self.all_tile_sprites.draw(self.static_sprite_surface) surface.blit(self.static_sprite_surface, (0, 0)) self.splat_sprites.draw(surface) if self.mouse_active_turret is not None: self.all_square_sprites.draw(surface) self.all_monster_sprites.draw(surface) self.all_turret_sprites.draw(surface) self.all_bullet_sprites.draw(surface) self.all_explosion_sprites.draw(surface) # collision debug # for monster in monsters: # monster.draw_collision_circle(screen) # for bullet in bullets: # bullet.draw_collision_rect(screen) for turret in self.turrets: if turret.show_radius: turret.draw_radius_circle(surface) if time_delta > 0.0 and self.fps_counter_label is not None: if len(self.frame_rates) < 300: self.frame_rates.append(1.0 / time_delta) else: self.frame_rates.popleft() self.frame_rates.append(1.0 / time_delta) fps = sum(self.frame_rates) / len(self.frame_rates) self.fps_counter_label.set_text("FPS: {:.2f}".format(fps)) if self.should_show_count_down_message and self.count_down_message_label is not None: self.count_down_message_label.set_text(self.count_down_message) if self.wave_display_label is not None and self.monster_wave_spawner.has_changed_wave: current_wave = str(self.monster_wave_spawner.current_wave_number) max_wave = str(self.monster_wave_spawner.maximum_wave_number) self.wave_display_label.set_text("Wave " + current_wave + "/" + max_wave) self.ui_manager.draw_ui(surface)