extends Node2D @onready var ground_layer: TileMapLayer = $GroundLayer @onready var path_layer: TileMapLayer = $PathLayer @onready var data_layer: TileMapLayer = $TestDataLayer @onready var navigation_graph: MPNavigationGraph = $NavigationGraph const DIRECTIONS: Dictionary = { "up": Vector2(0, -1), "down": Vector2(0, 1), "left": Vector2(-1, 0), "right": Vector2(1, 0) } var node_positions: Dictionary = {} func _ready() -> void: build_graph() func build_graph() -> void: print("Identifying nodes") # Step 1: Place nodes at positions where is_tile is true for position in data_layer.get_used_cells(): var tile_data: TileData = data_layer.get_cell_tile_data(position) var is_tile: bool = tile_data.get_custom_data("is_tile") if is_tile: var node: NavigationNode = navigation_graph.add_node(position.x, position.y) node_positions[position] = node print(Vector2(position)) # Step 2: Connect nodes using flood-fill based on walkable tiles print("Connecting nodes") for position in node_positions.keys(): connect_node(position) func connect_node(start_position: Vector2) -> void: var start_node = node_positions.get(Vector2i(start_position)) var visited: Dictionary = {} visited[start_position] = true print("Connecting node at ", start_position) # For each direction, perform flood-fill for dir_name in DIRECTIONS.keys(): var direction = DIRECTIONS[dir_name] var next_position = start_position + direction print("Checking direction ", dir_name, " from ", start_position, " to ", next_position) # Ensure the first tile respects the direction if not is_valid_direction(next_position, dir_name): continue print("Flood-fill in direction ", dir_name, " from ", next_position) # Perform flood-fill from the valid tile var connected_nodes: Array = flood_fill(next_position, visited) # Add connections between the start node and found nodes for target_position in connected_nodes: if target_position != start_position: if node_positions.has(Vector2i(target_position)): var target_node = node_positions.get(Vector2i(target_position)) navigation_graph.add_connection(start_node, target_node) print(start_position, " --> ", target_position) func flood_fill(start_position: Vector2, visited: Dictionary) -> Array: var stack: Array[Vector2] = [start_position] var connected_nodes: Array[Vector2] = [] while stack.size() > 0: var current_position = stack.pop_back() print(" - Visiting ", current_position) # Skip if already visited if visited.has(current_position): continue visited[current_position] = true # Skip if not walkable var tile_data: TileData = data_layer.get_cell_tile_data(current_position) if tile_data == null: continue var is_walkable: bool = tile_data.get_custom_data("is_walkable") var is_tile: bool = tile_data.get_custom_data("is_tile") if (not is_walkable) and (not is_tile): continue # If this position is a node, add it to the result if is_tile: print(" - Found node tile at ", current_position) connected_nodes.append(current_position) else: print(" - Found walkable tile at ", current_position) # Add neighboring tiles to the stack if they respect the direction for dir_name in DIRECTIONS.keys(): var direction = DIRECTIONS[dir_name] var neighbor_position = current_position + direction if not visited.has(neighbor_position): if is_valid_direction(current_position, dir_name): stack.append(neighbor_position) return connected_nodes func is_valid_direction(position: Vector2, required_dir: String) -> bool: var tile_data: TileData = data_layer.get_cell_tile_data(position) if tile_data == null: print(" L Cancelled due to null tile data") return false var is_walkable: bool = tile_data.get_custom_data("is_walkable") var walk_dir: String = tile_data.get_custom_data("walk_dir") # If walk_dir is empty, treat it as "any" direction if walk_dir == "": walk_dir = "any" print(" L ", position, " ", is_walkable, " ", walk_dir, " ", required_dir) # Check if the tile is walkable and allows movement in the required direction return is_walkable and (walk_dir == required_dir or walk_dir == "any")