def create_ai_at_random_position(self): for x in range(self._game_grid.grid_size.x): for y in range(self._game_grid.grid_size.y): if self._game_grid.cells[x][ y].walkable and self._game_grid.explosions[x][ y] is False: if Vector2(x, y).mahattan_distance( self._player_controller._grid_pos ) > self._game_grid.grid_size.x / 2: self.add_AI(Vector2(x, y)) return
def compute_world_position(self, grid_position: Vector2) -> Vector2: offset = self._grid.transform.position - (self._grid.dimensions / 2) world_position = Vector2(0, 0) world_position.x = grid_position.x * self._cell_size.x world_position.y = grid_position.y * self._cell_size.y world_position += offset world_position += self._cell_size / 2 return world_position
def find_lowest_f_cost_node( nodes: Dict[Vector2, AIAgent.ASNode]) -> AIAgent.ASNode: lowest_f_cost_node: AIAgent.ASNode = AIAgent.ASNode( Vector2(0, 0), None, 5000, 5000) for node in nodes.values(): if node.f_cost < lowest_f_cost_node.f_cost: lowest_f_cost_node = node return lowest_f_cost_node
def __init__(self, source: pygame.Surface, row_count: int, column_count: int): self.__source = source self.__sprite_size = Vector2(source.get_width() / column_count, source.get_height() / row_count) self.__sprite_matrix: List[List[pygame.Surface]] = list() self.__row_count = row_count self.__column_count = column_count self.__generate_sprite_matrix()
def on_init(self): self._sprite_renderer: core.core_components.SpriteRenderer = self.owner.get_component( core.core_components.SpriteRenderer) self._movement_disabled: bool = False self._target_position: Vector2 = Vector2(0, 0) self._mov_delta: Vector2 = Vector2(0, 0) self._fire_power = 5 self._max_bombs = 3 self._bomb_count = 0 self._mov_delta_factor = 10 self._movement_duration = (1 / 60) * self._mov_delta_factor self._frame_duration = self._movement_duration / 7 self._play_anim = False self._current_anim_frame: int = 0 self._last_frame_tp: float = 0 self._direction: Direction = Direction.SOUTH self._anim_type: int = 0 self.event_system.listen("bomb_exploded", self.return_bomb, sender=self) self.sheet = "player"
def __find_path_to_safety(self) -> AIAgent.ASNode: open_nodes: List[AIAgent.ASNode] = list() closed_nodes: Dict[Vector2, AIAgent.ASNode] = dict() open_nodes.append(AIAgent.ASNode(self._grid_pos, None, 0, 0)) danger_grid = self.__expand_bombs() if danger_grid[self._grid_pos.x][self._grid_pos.y] is False: return open_nodes[0] while open_nodes: q = open_nodes.pop(0) closed_nodes[q.position] = q successors: List[AIAgent.ASNode] = list() temp_pos = q.position + Vector2(0, 1) if temp_pos.y < self._grid_size.y and self._grid.cells[temp_pos.x][ temp_pos.y].walkable and temp_pos not in closed_nodes: successors.append(AIAgent.ASNode(temp_pos, q, 0, 0)) temp_pos = q.position + Vector2(0, -1) if temp_pos.y >= 0 and self._grid.cells[temp_pos.x][ temp_pos.y].walkable and temp_pos not in closed_nodes: successors.append(AIAgent.ASNode(temp_pos, q, 0, 0)) temp_pos = q.position + Vector2(1, 0) if temp_pos.x < self._grid_size.y and self._grid.cells[temp_pos.x][ temp_pos.y].walkable and temp_pos not in closed_nodes: successors.append(AIAgent.ASNode(temp_pos, q, 0, 0)) temp_pos = q.position + Vector2(-1, 0) if temp_pos.x >= 0 and self._grid.cells[temp_pos.x][ temp_pos.y].walkable and temp_pos not in closed_nodes: successors.append(AIAgent.ASNode(temp_pos, q, 0, 0)) open_nodes.extend(successors) for succ in successors: if danger_grid[succ.position.x][succ.position.y] is False: return succ
def update(self): self.transform.position += self._mov_delta if (self._play_anim): if (time.perf_counter() - self._last_frame_tp >= self._frame_duration): self._last_frame_tp = time.perf_counter() self._sprite_renderer.sprite = self.app.image_loader.get_sheet( self.sheet)[0][self._anim_type] self._current_anim_frame += 1 if (self.transform.position - self._target_position).squared_mag <= 0.15: self._play_anim = False self._current_anim_frame = 0 self.transform.position = self._target_position self._movement_disabled = False self._mov_delta = Vector2(0, 0) self.__set_end_sprite() if (self._grid.explosions[self._grid_pos.x][self._grid_pos.y]): self.world.mark_entity_for_deletion(self.owner) self.on_death()
def start_game(self): self._menu_canvas.hide() self._game_over_canvas.hide() self._game_grid_entity = self.world.add_entity() self._game_grid_entity.add_component( core.core_components.SpriteRenderer) self._game_grid: GameGrid = self._game_grid_entity.add_component( GameGrid) self._game_grid.generate_grid(Vector2(17, 17), Vector2(32, 32)) self._player_entity = self.world.add_entity() self._player_entity.add_component(core.core_components.SpriteRenderer) self._player_controller: Player = self._player_entity.add_component( Player) self._player_controller.set_grid(self._game_grid, Vector2(0, 0)) self.add_AI(Vector2(0, 16)) self.add_AI(Vector2(16, 0)) self.add_AI(Vector2(16, 16))
def dimensions(self) -> Vector2: return Vector2(self.__grid_size.x * self.__cell_size.x, self.__grid_size.y * self.__cell_size.y)
def _move_down(self, *args): self.move(Vector2(0, 1))
def generate_grid(self, grid_size: Vector2, cell_size: Vector2): self.__grid_size = grid_size self.__cell_size = cell_size self.__grid_cells: List[List[GridCell]] = list() self.__grid_image: pygame.Surface = pygame.Surface( (grid_size.x * cell_size.x, grid_size.y * cell_size.y)) self.__grid_bombs: List[List[Optional[Bomb]]] = list() self.__grid_explosions: List[List[bool]] = list() for x in range(self.__grid_size.x): column: List[GridCell] = list() bomb_column: List[Optional[Bomb]] = list() explosion_column: List[bool] = list() for y in range(self.__grid_size.y): if (x + 1) % 2 == 0 and (y + 1) % 2 == 0: cell = GridCell(self.app.image_loader.get_image("ob"), Vector2(x, y), self.event_system, False, False) else: cell = GridCell(self.app.image_loader.get_image("wall"), Vector2(x, y), self.event_system, False, True) self.event_system.listen("cell_img_changed", self.update_grid_img, sender=cell) column.append(cell) bomb_column.append(None) explosion_column.append(False) self.__grid_cells.append(column) self.__grid_bombs.append(bomb_column) self.__grid_explosions.append(explosion_column) self.__grid_cells[0][0].image = self.app.image_loader.get_image("dirt") self.__grid_cells[0][1].image = self.app.image_loader.get_image("dirt") self.__grid_cells[1][0].image = self.app.image_loader.get_image("dirt") self.__grid_cells[0][0].walkable = True self.__grid_cells[0][1].walkable = True self.__grid_cells[1][0].walkable = True self.__grid_cells[0][0].destructible = False self.__grid_cells[0][1].destructible = False self.__grid_cells[1][0].destructible = False self.__grid_cells[self.__grid_size.x - 1][self.__grid_size.y - 1].image = self.app.image_loader.get_image("dirt") self.__grid_cells[self.__grid_size.x - 2][self.__grid_size.y - 1].image = self.app.image_loader.get_image("dirt") self.__grid_cells[self.__grid_size.x - 1][self.__grid_size.y - 2].image = self.app.image_loader.get_image("dirt") self.__grid_cells[self.__grid_size.x - 1][self.__grid_size.y - 1].walkable = True self.__grid_cells[self.__grid_size.x - 2][self.__grid_size.y - 1].walkable = True self.__grid_cells[self.__grid_size.x - 1][self.__grid_size.y - 2].walkable = True self.__grid_cells[self.__grid_size.x - 1][self.__grid_size.y - 1].destructible = False self.__grid_cells[self.__grid_size.x - 2][self.__grid_size.y - 1].destructible = False self.__grid_cells[self.__grid_size.x - 1][self.__grid_size.y - 2].destructible = False self.__grid_cells[self.__grid_size.x - 1][0].image = self.app.image_loader.get_image("dirt") self.__grid_cells[self.__grid_size.x - 2][0].image = self.app.image_loader.get_image("dirt") self.__grid_cells[self.__grid_size.x - 1][1].image = self.app.image_loader.get_image("dirt") self.__grid_cells[self.__grid_size.x - 1][0].walkable = True self.__grid_cells[self.__grid_size.x - 2][0].walkable = True self.__grid_cells[self.__grid_size.x - 1][1].walkable = True self.__grid_cells[self.__grid_size.x - 1][0].destructible = False self.__grid_cells[self.__grid_size.x - 2][0].destructible = False self.__grid_cells[self.__grid_size.x - 1][1].destructible = False self.__grid_cells[0][self.__grid_size.y - 1].image = self.app.image_loader.get_image("dirt") self.__grid_cells[1][self.__grid_size.y - 1].image = self.app.image_loader.get_image("dirt") self.__grid_cells[0][self.__grid_size.y - 2].image = self.app.image_loader.get_image("dirt") self.__grid_cells[0][self.__grid_size.y - 1].walkable = True self.__grid_cells[1][self.__grid_size.y - 1].walkable = True self.__grid_cells[0][self.__grid_size.y - 2].walkable = True self.__grid_cells[0][self.__grid_size.y - 1].destructible = False self.__grid_cells[1][self.__grid_size.y - 1].destructible = False self.__grid_cells[0][self.__grid_size.y - 2].destructible = False self.generate_grid_image() self.centralize_grid_in_screen()
def find_path(self, end_pos: Vector2, ignore_walkability: bool = False, ignore_danger: bool = False): open_nodes: Dict[Vector2, AIAgent.ASNode] = dict() closed_nodes: Dict[Vector2, AIAgent.ASNode] = dict() open_nodes[self._grid_pos] = AIAgent.ASNode(self._grid_pos, None, 0, 0) danger_grid: List[List[bool]] = self.__expand_bombs() if end_pos == self._grid_pos: return def find_lowest_f_cost_node( nodes: Dict[Vector2, AIAgent.ASNode]) -> AIAgent.ASNode: lowest_f_cost_node: AIAgent.ASNode = AIAgent.ASNode( Vector2(0, 0), None, 5000, 5000) for node in nodes.values(): if node.f_cost < lowest_f_cost_node.f_cost: lowest_f_cost_node = node return lowest_f_cost_node while open_nodes: q: AIAgent.ASNode = find_lowest_f_cost_node(open_nodes) del open_nodes[q.position] successsors: List[AIAgent.ASNode] = list() temp_pos = q.position + Vector2(0, 1) if temp_pos.y < self._grid_size.y and ( self._grid.cells[temp_pos.x][temp_pos.y].walkable or (ignore_walkability and self._grid.cells[temp_pos.x][temp_pos.y].destructible)) and ( (self._grid.explosions[temp_pos.x][temp_pos.y] is False and danger_grid[temp_pos.x][temp_pos.y] is False) or ignore_danger): successsors.append( AIAgent.ASNode(temp_pos, q, q.g_cost + 1, temp_pos.mahattan_distance(end_pos))) temp_pos = q.position + Vector2(0, -1) if temp_pos.y >= 0 and ( self._grid.cells[temp_pos.x][temp_pos.y].walkable or (ignore_walkability and self._grid.cells[temp_pos.x][temp_pos.y].destructible)) and ( (self._grid.explosions[temp_pos.x][temp_pos.y] is False and danger_grid[temp_pos.x][temp_pos.y] is False) or ignore_danger): successsors.append( AIAgent.ASNode(temp_pos, q, q.g_cost + 1, temp_pos.mahattan_distance(end_pos))) temp_pos = q.position + Vector2(1, 0) if temp_pos.x < self._grid_size.x and ( self._grid.cells[temp_pos.x][temp_pos.y].walkable or (ignore_walkability and self._grid.cells[temp_pos.x][temp_pos.y].destructible)) and ( (self._grid.explosions[temp_pos.x][temp_pos.y] is False and danger_grid[temp_pos.x][temp_pos.y] is False) or ignore_danger): successsors.append( AIAgent.ASNode(temp_pos, q, q.g_cost + 1, temp_pos.mahattan_distance(end_pos))) temp_pos = q.position + Vector2(-1, 0) if temp_pos.x >= 0 and ( self._grid.cells[temp_pos.x][temp_pos.y].walkable or (ignore_walkability and self._grid.cells[temp_pos.x][temp_pos.y].destructible)) and ( (self._grid.explosions[temp_pos.x][temp_pos.y] is False and danger_grid[temp_pos.x][temp_pos.y] is False) or ignore_danger): successsors.append( AIAgent.ASNode(temp_pos, q, q.g_cost + 1, temp_pos.mahattan_distance(end_pos))) for succ in successsors: if succ.position == end_pos: return succ if succ.position in open_nodes: if open_nodes[succ.position].f_cost < succ.f_cost: continue elif succ.position in closed_nodes: if closed_nodes[succ.position].f_cost < succ.f_cost: continue else: open_nodes[succ.position] = succ closed_nodes[q.position] = q
def _move_left(self, *args): self.move(Vector2(-1, 0))
def on_explode(self, incoming_direction: Optional[Direction] = None): self.event_system.broadcast("bomb_exploded", sender=self.__owner) self._grid.cells[self._grid_pos.x][self._grid_pos.y].walkable = True self._grid.bombs[self._grid_pos.x][self._grid_pos.y] = None self.world.mark_entity_for_deletion(self.owner) firepower = self.__owner.firepower expand_east: bool = True if incoming_direction != Direction.EAST else False expand_west: bool = True if incoming_direction != Direction.WEST else False expand_north: bool = True if incoming_direction != Direction.NORTH else False expand_south: bool = True if incoming_direction != Direction.SOUTH else False if incoming_direction is None: self.app.sound_loader.play_sound("explosion") self.create_explosion(Direction.CENTER, self._grid_pos) for val in range(1, firepower + 1): final_iteration = val == firepower if expand_west: target_x = self._grid_pos.x - val if target_x >= 0: target_cell: GridCell = self._grid.cells[target_x][ self._grid_pos.y] target_bomb: Bomb = self._grid.bombs[target_x][ self._grid_pos.y] if target_cell.destructible: target_cell.destructible = False target_cell.walkable = True target_cell.image = self.app.image_loader.get_image( "dirt") self.create_explosion(Direction.WEST, Vector2(target_x, self._grid_pos.y), end=True) expand_west = False elif target_bomb is not None: target_bomb.on_explode(Direction.EAST) expand_west = False elif target_cell.walkable: self.create_explosion(Direction.WEST, Vector2(target_x, self._grid_pos.y), end=(target_x == 0 or final_iteration)) else: expand_west = False if expand_east: target_x = self._grid_pos.x + val if target_x < self._grid_size.x: target_cell: GridCell = self._grid.cells[target_x][ self._grid_pos.y] target_bomb: Bomb = self._grid.bombs[target_x][ self._grid_pos.y] if target_cell.destructible: target_cell.destructible = False target_cell.walkable = True target_cell.image = self.app.image_loader.get_image( "dirt") self.create_explosion(Direction.EAST, Vector2(target_x, self._grid_pos.y), end=True) expand_east = False elif target_bomb is not None: target_bomb.on_explode(Direction.WEST) expand_east = False elif target_cell.walkable: self.create_explosion( Direction.EAST, Vector2(target_x, self._grid_pos.y), end=(target_x == self._grid_size.x - 1 or final_iteration)) else: expand_east = False if expand_north: target_y = self._grid_pos.y - val if target_y >= 0: target_cell: GridCell = self._grid.cells[ self._grid_pos.x][target_y] target_bomb: Bomb = self._grid.bombs[ self._grid_pos.x][target_y] if target_cell.destructible: target_cell.destructible = False target_cell.walkable = True target_cell.image = self.app.image_loader.get_image( "dirt") self.create_explosion(Direction.NORTH, Vector2(self._grid_pos.x, target_y), end=True) expand_north = False elif target_bomb is not None: target_bomb.on_explode(Direction.SOUTH) expand_north = False elif target_cell.walkable: self.create_explosion(Direction.NORTH, Vector2(self._grid_pos.x, target_y), end=(target_y == 0 or final_iteration)) else: expand_north = False if expand_south: target_y = self._grid_pos.y + val if target_y < self._grid_size.y: target_cell: GridCell = self._grid.cells[ self._grid_pos.x][target_y] target_bomb: Bomb = self._grid.bombs[ self._grid_pos.x][target_y] if target_cell.destructible: target_cell.destructible = False target_cell.walkable = True target_cell.image = self.app.image_loader.get_image( "dirt") self.create_explosion(Direction.SOUTH, Vector2(self._grid_pos.x, target_y), end=True) expand_south = False elif target_bomb is not None: target_bomb.on_explode(Direction.NORTH) expand_south = False elif target_cell.walkable: self.create_explosion( Direction.SOUTH, Vector2(self._grid_pos.x, target_y), end=(target_y == self._grid_size.y - 1 or final_iteration)) else: expand_south = False if not expand_east and not expand_west and not expand_south and not expand_north: break
def _move_right(self, *args): self.move(Vector2(1, 0))
def _move_up(self, *args): self.move(Vector2(0, -1))
def centralize_grid_in_screen(self): self.transform.position = Vector2(self.app.display.get_width() / 2, self.app.display.get_height() / 2)
def on_init(self): self._menu_canvas: core.core_components.Canvas = self.owner.add_component( core.core_components.Canvas) self._play_button = core.core_components.Button( Vector2(600, 200), self._menu_canvas) self._play_button.text = "JOGAR" self._play_button.foreground_color = (0, 210, 210, 255) self._quit_button = core.core_components.Button( Vector2(600, 350), self._menu_canvas) self._quit_button.text = "SAIR" self._quit_button.foreground_color = (0, 210, 210, 255) self._main_text = core.core_components.Button(Vector2(600, 50), self._menu_canvas) self._main_text.text = "py-BOMBERMAN" self._main_text.font_size = 50 self._main_text.foreground_color = (0, 0, 0, 0) self._main_text.size = (600, 300) self._play_button.on_click = self.start_game self._quit_button.on_click = lambda: exit(0) self._game_over_canvas: core.core_components.Canvas = self.owner.add_component( core.core_components.Canvas) self._retry_button = core.core_components.Button( Vector2(600, 200), self._game_over_canvas) self._retry_button.foreground_color = (0, 210, 210, 255) self._retry_button.text = "TENTAR NOVAMENTE" self._retry_button.on_click = self.start_game self._main_menu_button = core.core_components.Button( Vector2(600, 350), self._game_over_canvas) self._main_menu_button.foreground_color = (0, 210, 210, 255) self._main_menu_button.text = "VOLTAR PARA O MENU PRINCIPAL" self._main_menu_button.on_click = self._game_over_to_main_menu self._game_over_text = core.core_components.Button( Vector2(600, 50), self._game_over_canvas) self._game_over_text.text = "GAME OVER" self._game_over_text.font_size = 30 self._game_over_text.foreground_color = (0, 0, 0, 0) self._final_score_text = core.core_components.Button( Vector2(600, 450), self._game_over_canvas) self._final_score_text.foreground_color = (0, 0, 0, 0) self._highest_score_text = core.core_components.Button( Vector2(600, 500), self._game_over_canvas) self._highest_score_text.foreground_color = (0, 0, 0, 0) self._new_record_text = core.core_components.Button( Vector2(600, 650), self._game_over_canvas) self._new_record_text.text = "" self._new_record_text.foreground_color = (0, 0, 0, 0) self._game_over_canvas.hide() self._ai_count = 0 self._ai_list: List[core.entity_system.Entity] = list() self.event_system.listen("ai_death", self.on_ai_death) self.event_system.listen("player_death", self.on_player_death) self._actions: List[Tuple[Callable, float]] = list() self._highest_score = 0 self.load_highest_score() self._current_score = 0 pygame.display.set_icon(self.app.image_loader.get_image("bomb"))