## LevelManager.gd # Manages the current level's data, visual representation, and navigation graph. # Responsible for generating, painting, and initializing the level, as well as providing pathfinding and coordinate helpers. extends Node const ENEMY_SCENE_PATH: String = "res://scenes/actors/enemy.tscn" # The source of truth for the current level's layout (MapData resource). var _data: MapData # The TileMapLayer node where the map is visually rendered. var _layer: TileMapLayer # Service objects for map generation, painting, and pathfinding. # MapGenerator and MapPainter are stateless; PathfindingHandler manages the navigation graph. var _generator: MapGenerator = MapGenerator.new() var _painter: MapPainter = MapPainter.new() var _pathfinding: PathfindingHandler = PathfindingHandler.new() # Orchestrates the creation of a new level. # 1. Generates the map data. # 2. Paints the map visually. # 3. Builds the navigation graph for AI/pathfinding. # 4. Spawns the player at the correct location. func initialize(settings: MapSettings, layer: TileMapLayer, player: Player) -> void: _layer = layer # 1. Generate the abstract map data (rooms, corridors, etc.). # This avoids side effects on the settings resource. _data = _generator.generate(settings) # 2. Paint the visual layer for the player to see. # This does not modify the underlying map data. _painter.paint(_data, _layer) # 3. Build the AStar graph for AI and navigation. # Reads directly from the grid stored in _data. _pathfinding.build(_data) # 4. Finalize world state by spawning the player at the spawn point. # Uses the TileMapLayer to convert grid coordinates to world pixel positions. player.position = _layer.map_to_local(_data.spawn_point) # 5. Spawn one enemy per room, skipping the player's spawn room (index 0). var enemy_scene := load(ENEMY_SCENE_PATH) as PackedScene var world_node := player.get_parent() for i in range(1, _data.rooms.size()): var enemy_instance = enemy_scene.instantiate() var enemy = enemy_instance as Enemy if enemy == null: push_error("Failed to cast enemy instance to Enemy at room index %d" % i) continue enemy._player = player world_node.add_child(enemy) enemy.position = _layer.map_to_local(_data.rooms[i].get_center()) # Public API for other systems (like AI) to query the navigation grid. # Encapsulates the PathfindingHandler so callers don't need to know about it directly. func find_path(from: Vector2i, to: Vector2i) -> Array[Vector2i]: return _pathfinding.find_path(from, to) # Coordinate conversion helpers — lets the player and other systems convert between world and tile coordinates without touching the TileMapLayer directly. func world_to_tile(world_pos: Vector2) -> Vector2i: return _layer.local_to_map(world_pos) func tile_to_world(tile: Vector2i) -> Vector2: return _layer.map_to_local(tile)