from typing import Optional from level.Level import Level from level.elements.dynamic.BouncingBallLevelElement import BouncingBallLevelElement from level.elements.dynamic.PushableBoxLevelElement import PushableBoxLevelElement from level.elements.static.GoalDoorReceiverLevelElement import GoalDoorReceiverLevelElement from level.elements.static.SpikeLevelElement import SpikeLevelElement from level.elements.static.ButtonInputLevelElement import ButtonInputLevelElement from level.elements.static.GateReceiverLevelElement import GateReceiverLevelElement from level.elements.LevelElement import LevelElement from level.elements.static.LeverInputLevelElement import LeverInputLevelElement from level.elements.static.SimpleBlockLevelElement import SimpleBlockLevelElement from level.elements.static.UnknownTileLevelElement import UnknownTileLevelElement from physics import ConstantsParser from physics.SpriteManager import SpriteManager, DrawLayers from physics.sprites.PlayerSprite import PlayerSprite from sprite.PositionScale import PositionScale from sprite.SpritesheetManager import SpritesheetManager TILES = { '#': SimpleBlockLevelElement, '+': SimpleBlockLevelElement, '-': SimpleBlockLevelElement, 'l': SimpleBlockLevelElement, 'r': SimpleBlockLevelElement, '~': SimpleBlockLevelElement, '|': SimpleBlockLevelElement, 'P': ButtonInputLevelElement, 'L': LeverInputLevelElement, 'G': GateReceiverLevelElement, 'D': GoalDoorReceiverLevelElement, 'M': PushableBoxLevelElement, 'q': BouncingBallLevelElement, 'S': SpikeLevelElement, 's': SpikeLevelElement, '<': SpikeLevelElement, '>': SpikeLevelElement } class LoadedLevel: def __init__(self, sprite_manager: SpriteManager, spritesheet_manager: SpritesheetManager): self.sprite_manager = sprite_manager self.spritesheet_manager = spritesheet_manager self.blocks = [] self.elements_by_id: dict[str, LevelElement] = {} def load_level(self, level: Level): for row_number, row in enumerate(level.tiles): for tile_number, tile in enumerate(row): world_position = (tile_number, row_number) position = (tile_number * ConstantsParser.CONFIG.block_size[0], row_number * ConstantsParser.CONFIG.block_size[1]) tile['world_position'] = world_position tile['position'] = position name = tile['name'] element = None if name in TILES: element = TILES[name](tile, self) elif name == 'C': ghost_character = PlayerSprite(self.spritesheet_manager.get_sheet("ghost_character")) ghost_character.position_scale = PositionScale((position[0], position[1]), (1, 1)) self.sprite_manager.add_ui_element(DrawLayers.OBJECTS, ghost_character) elif not name == '': print(f"Unknown tile at {position}: {name}") element = UnknownTileLevelElement(tile, self) if element: self.blocks.append(element) self.sprite_manager.add_ui_element(DrawLayers.OBJECTS, element) element.load(self.sprite_manager, self.spritesheet_manager, level) self.elements_by_id[element.id] = element if isinstance(element, SimpleBlockLevelElement): if self.is_surrounded_by_blocks(world_position, level.tiles): element.is_collider = False element.register_collisions = False # self.sprite_manager.remove_ui_element(element) def get_element_by_id(self, search_id: str) -> Optional[LevelElement]: if search_id in self.elements_by_id: return self.elements_by_id[search_id] return None def is_surrounded_by_blocks(self, position, tiles): for i in range(-1, 2): for j in range(-1, 2): if i == 0 and j == 0: continue if position[0] + i < 0 or position[0] + i >= len(tiles[0]): continue if position[1] + j < 0 or position[1] + j >= len(tiles): continue tile = tiles[position[1] + j][position[0] + i] if not tile['name'] in ['#', '+', '-', 'l', 'r', '~', '|']: return False return True def destroy_level(self): for block in self.blocks: self.sprite_manager.remove_ui_element(block) del self.blocks self.blocks = []