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.InvisibleElement import InvisibleElement from level.elements.static.VacuumCleanerElement import VacuumCleanerElement 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, 'A': VacuumCleanerElement, 'i': InvisibleElement } BACK_LAYER = [ ] FRONT_LAYER = [ 'M' ] 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] = {} self.level_screen_manager = None def load_level(self, level: Level): # create a wall of InvisibleElement around the level left and right # block_left = SimpleBlockLevelElement({'name': '#', 'position': (30, 300)}, self, self.level_screen_manager) # block_left.load(self.sprite_manager, self.spritesheet_manager, level) # self.blocks.append(block_left) # self.sprite_manager.add_ui_element(DrawLayers.OBJECTS_BACK, block_left) for i in range(0, 100): block_left = InvisibleElement({'name': 'i', 'position': (-16, i * 32)}, self, self.level_screen_manager) block_left.load(self.sprite_manager, self.spritesheet_manager, level) self.blocks.append(block_left) self.sprite_manager.add_ui_element(DrawLayers.OBJECTS_BACK, block_left) for i in range(0, 100): block_right = InvisibleElement({'name': 'i', 'position': (ConstantsParser.CONFIG.block_size[0] * ConstantsParser.CONFIG.level_size[0] + 4, i * 32)}, self, self.level_screen_manager) block_right.load(self.sprite_manager, self.spritesheet_manager, level) self.blocks.append(block_right) self.sprite_manager.add_ui_element(DrawLayers.OBJECTS_BACK, block_right) 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 layer = DrawLayers.OBJECTS if name in TILES: element = TILES[name](tile, self, self.level_screen_manager) if name in BACK_LAYER: layer = DrawLayers.OBJECTS_BACK elif name in FRONT_LAYER: layer = DrawLayers.OBJECTS_FRONT elif name == 'C': ghost_character = PlayerSprite(self.spritesheet_manager.get_sheet("ghost_character")) ghost_character.position_scale = PositionScale((position[0], position[1]), (1, 1)) layer = DrawLayers.PLAYER self.blocks.append(ghost_character) self.sprite_manager.add_ui_element(layer, ghost_character) elif not name == '': print(f"Unknown tile at {position}: {name}") element = UnknownTileLevelElement(tile, self, self.level_screen_manager) if element: self.blocks.append(element) self.sprite_manager.add_ui_element(layer, 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 = []