""" ICE WALKER GAME RUNNER The main file that runs the game itself """ import objects import json import pyxel from os.path import exists CELL_SIZE = 8 GRID_X = 11 GRID_Y = 6 WIN_X = CELL_SIZE*GRID_X WIN_Y = CELL_SIZE*GRID_Y def load_file_json(lvl: int) -> list: """ :param lvl: (int) The id of the level to load :return: (list) The loaded level from the file Reads the corresponding level file and returns its loaded content """ file = open(f"lvl_json/{lvl}.json", "r", encoding="utf-8") decoder = json.JSONDecoder() return decoder.decode(file.read()) def load_file(lvl: int) -> list: """ :param lvl: (int) The id of the level to load :return: (list) The loaded level from the file Reads the corresponding level file and returns its loaded content """ file = open(f"lvl/{lvl}.dat", "rb") content = file.read() res = [] mem = [] for v in content: if int(v) == 255: res.append(mem) mem = [] else: mem.append(int(v)) return res def can_load(lvl: int) -> bool: """ :param lvl: (int) The id of the file to check for :return: (bool) Returns if the level file exists and can be loaded Tests if a level can be loaded, returns the result as a boolean """ return exists(f"lvl/{lvl}.dat") class LevelManager: """ This class is responsible for handling game data """ def __init__(self): self.current_level = 0 self.cache = [] def load_level(self, lvl: int): """ :param lvl: (int) The id of the level to load Loads the specified level and stores it into the cache """ print(f"Loading level {lvl}") if can_load(lvl): self.cache = load_file(lvl) self.current_level = lvl else: print("level doesn't exist") def load_collection_from_cache(self, collection: objects.Collection) -> objects.Player | None: """ :param collection: (Collection) The collection to load the objects into :return: The player object created by this method Loads the level elements using the loaded cache, returns the new player instance """ new_player = None for y in range(len(self.cache)): for x in range(len(self.cache[y])): element_id = self.cache[y][x] elt = objects.get_type_from_id(element_id) if elt: new = elt() new.position = objects.V2(x, y) collection.add(new) if element_id == 3: new_player = new return new_player class Game: """ This class manages the game runtime """ def __init__(self): self.level = None # An instance of the LevelManager class self.main_collection = None # An instance of Collection, usually the main one self.player = None # The current instance of the Player object def _upd(self): if self.player: direction = objects.V2() if pyxel.btnp(pyxel.KEY_Z): # Determine move direction direction.Y = -1 elif pyxel.btnp(pyxel.KEY_S): direction.Y = 1 elif pyxel.btnp(pyxel.KEY_Q): direction.X = -1 elif pyxel.btnp(pyxel.KEY_D): direction.X = 1 if not direction.is_zero(): # Handles the actual movement and collisions new_pos, colliders = self.main_collection.ray_cast(self.player.position, direction, self.player) self.player.position = new_pos for v in colliders: v.touched(self.player) if self.main_collection.exits == 0: # Handles when the level was cleared self.level.load_level(self.level.current_level + 1) self.main_collection.clear_all() new_player = self.level.load_collection_from_cache(self.main_collection) self.player = new_player def _display(self): pyxel.cls(0) for v in self.main_collection.get_objects(): # Render all active objects if isinstance(v, objects.MapObject): v.draw() elif isinstance(v, objects.Collection) and v.visible: # Render embedded collections, if visible for embed_v in v.get_objects(): embed_v.draw() def run(self, lvl_m: LevelManager, main_c: objects.Collection): """ :param lvl_m: (LevelManager) The instance of LevelManager to assign with the game instance :param main_c: (Collection) The primary collection containing the entirety of the game Initializes and runs the game """ self.level = lvl_m self.main_collection = main_c pyxel.init(WIN_X, WIN_Y, title="ice_walker") pyxel.run(self._upd, self._display) if __name__ == "__main__": main_collection = objects.Collection() level = LevelManager() # Load the first level of the game level.load_level(1) player = level.load_collection_from_cache(main_collection) game = Game() # Initializes the game engine game.player = player game.run(level, main_collection)