@tool class_name EnhancedGridMap extends GridMap signal mesh_library_changed signal grid_updated @export var columns: int = 10 : set = set_columns @export var rows: int = 10 : set = set_rows @export var floors: int = 3 : set = set_floors @export var auto_generate: bool = false : set = set_auto_generate @export var normal_items: Array[int] = [0] @export var non_walkable_items: Array[int] = [4] @export var hover_item: int = 1 @export var start_item: int = 2 @export var end_item: int = 3 var current_mesh_library: MeshLibrary var grid_data: Array = [] # 3D array [floor][row][column] # A* Pathfinding variables (per floor) var astar_by_floor = {} # Dictionary of AStar2D instances per floor var path = [] # Update the obstacle items array to use your specified item indices @export var obstacle_items: Array[int] = [12, 13, 14, 15] # Obstacle items in mesh library @export var obstacle_directions: Dictionary = {} # Store direction for each placed obstacle: {Vector3i position: Direction} # Direction and movement systems enum Direction { NORTHWEST, NORTH, NORTHEAST, WEST, CENTER, EAST, SOUTHWEST, SOUTH, SOUTHEAST, BLOCKED_NORTH = 10, BLOCKED_EAST = 11, BLOCKED_SOUTH = 12, BLOCKED_WEST = 13 } var diagonal_movement: bool = false class NeighborInfo: var position: Vector2i var direction: Direction var is_walkable: bool func _init(pos: Vector2i, dir: Direction, walkable: bool): position = pos direction = dir is_walkable = walkable func _ready(): mesh_library_changed.connect(_on_mesh_library_changed) if not Engine.is_editor_hint() and auto_generate: generate_grid() validate_item_indices() # Core grid management functions func set_columns(value: int): columns = value if auto_generate: generate_grid() else: update_grid_data() func set_rows(value: int): rows = value if auto_generate: generate_grid() else: update_grid_data() func set_floors(value: int): floors = value if auto_generate: generate_grid() else: update_grid_data() func set_auto_generate(value: bool): auto_generate = value if auto_generate: generate_grid() # Item validation func validate_item_indices(): if not mesh_library: print("Warning: No MeshLibrary assigned to GridMap") return var item_list = mesh_library.get_item_list() var max_index = item_list.size() - 1 normal_items = normal_items.filter(func(item): return item >= 0 and item <= max_index) hover_item = clamp(hover_item, 0, max_index) start_item = clamp(start_item, 0, max_index) end_item = clamp(end_item, 0, max_index) non_walkable_items = non_walkable_items.filter(func(item): return item >= 0 and item <= max_index) if normal_items.is_empty(): normal_items = [0] if non_walkable_items.is_empty(): non_walkable_items = [max_index] # Grid generation and management func generate_grid(floor_index: int = -1): if floor_index == -1: clear() for y in range(floors): generate_floor(y) else: clear_floor(floor_index) generate_floor(floor_index) update_grid_data() initialize_astar() update_astar_costs() func generate_floor(floor_index: int): if not mesh_library: print("Error: No MeshLibrary assigned to GridMap") return validate_item_indices() current_mesh_library = mesh_library var item_list = mesh_library.get_item_list() if item_list.size() < 5: print("Warning: MeshLibrary should have at least 5 items") for x in range(columns): for z in range(rows): set_cell_item(Vector3i(x, floor_index, z), normal_items[0]) # Grid operations func clear_floor(floor_index: int): for x in range(columns): for z in range(rows): set_cell_item(Vector3i(x, floor_index, z), -1) update_grid_data() func clear_grid(floor_index: int = -1): if floor_index == -1: clear() else: clear_floor(floor_index) update_grid_data() func fill_grid(item_index: int, floor_index: int = -1): if not mesh_library: print("No MeshLibrary assigned to GridMap") return if item_index < 0 or item_index >= mesh_library.get_item_list().size(): print("Invalid item index") return if floor_index == -1: for y in range(floors): fill_floor(item_index, y) else: if floor_index >= 0 and floor_index < floors: fill_floor(item_index, floor_index) else: print("Invalid floor index") update_grid_data() initialize_astar() update_astar_costs() func fill_floor(item_index: int, floor_index: int): for x in range(columns): for z in range(rows): var cell_pos = Vector3i(x, floor_index, z) var current_orientation = get_cell_item_orientation(cell_pos) set_cell_item(cell_pos, item_index, current_orientation) # Randomization functions func randomize_grid(floor_index: int = -1): if floor_index == -1: for y in range(floors): randomize_floor(y) else: randomize_floor(floor_index) update_grid_data() initialize_astar() update_astar_costs() func randomize_floor(floor_index: int): if not mesh_library: print("Error: No MeshLibrary assigned to GridMap") return validate_item_indices() var rng = RandomNumberGenerator.new() rng.randomize() for x in range(columns): for z in range(rows): var random_value = rng.randi() % 100 var item_index if random_value < 80: item_index = normal_items[rng.randi() % normal_items.size()] else: item_index = non_walkable_items[rng.randi() % non_walkable_items.size()] set_cell_item(Vector3i(x, floor_index, z), item_index) func randomize_grid_custom(randomize_states: Array, floor_index: int = -1): if not mesh_library: print("Error: No MeshLibrary assigned to GridMap") return if floor_index == -1: for y in range(floors): randomize_floor_custom(randomize_states, y) else: if floor_index >= 0 and floor_index < floors: randomize_floor_custom(randomize_states, floor_index) else: print("Invalid floor index") update_grid_data() initialize_astar() update_astar_costs() func randomize_floor_custom(randomize_states: Array, floor_index: int): if randomize_states.is_empty(): print("No randomize states provided") return var rng = RandomNumberGenerator.new() rng.randomize() for x in range(columns): for z in range(rows): var cell_pos = Vector3i(x, floor_index, z) var random_value = rng.randf() * 100 var accumulated_percentage = 0 var selected_state = null for state in randomize_states: if state.include_in_randomize: accumulated_percentage += state.randomize_percentage if random_value <= accumulated_percentage: selected_state = state break var current_orientation = get_cell_item_orientation(cell_pos) if selected_state: set_cell_item(cell_pos, selected_state.id, current_orientation) else: var fallback_state = null for state in randomize_states: if state.include_in_randomize: fallback_state = state break if fallback_state: set_cell_item(cell_pos, fallback_state.id, current_orientation) else: set_cell_item(cell_pos, normal_items[0], current_orientation) #func get_neighbors(current_pos: Vector2i, floor_index: int) -> Array[NeighborInfo]: #var neighbors: Array[NeighborInfo] = [] # #var directions = { #Direction.NORTHWEST: Vector2i(-1, -1), #Direction.NORTH: Vector2i(0, -1), #Direction.NORTHEAST: Vector2i(1, -1), #Direction.WEST: Vector2i(-1, 0), #Direction.EAST: Vector2i(1, 0), #Direction.SOUTHWEST: Vector2i(-1, 1), #Direction.SOUTH: Vector2i(0, 1), #Direction.SOUTHEAST: Vector2i(1, 1) #} # #for dir in directions: #var offset = directions[dir] #var neighbor_pos = current_pos + offset # #if is_position_valid(neighbor_pos): #var is_walkable = is_cell_walkable(neighbor_pos, floor_index) # ## Check for obstacles - specifically for orthogonal movement #if not is_diagonal_direction(dir) and is_blocked_by_obstacle(current_pos, neighbor_pos, 3): #is_walkable = false # ## Special handling for diagonal movement #if is_diagonal_direction(dir): #var adjacent1: Vector2i #var adjacent2: Vector2i # #match dir: #Direction.NORTHWEST: #adjacent1 = current_pos + Vector2i(-1, 0) # West #adjacent2 = current_pos + Vector2i(0, -1) # North #Direction.NORTHEAST: #adjacent1 = current_pos + Vector2i(1, 0) # East #adjacent2 = current_pos + Vector2i(0, -1) # North #Direction.SOUTHWEST: #adjacent1 = current_pos + Vector2i(-1, 0) # West #adjacent2 = current_pos + Vector2i(0, 1) # South #Direction.SOUTHEAST: #adjacent1 = current_pos + Vector2i(1, 0) # East #adjacent2 = current_pos + Vector2i(0, 1) # South # ## For diagonal movement, both adjacent cells must be walkable ## AND the movements to those adjacent cells must not be blocked #is_walkable = is_walkable and \ #is_position_valid(adjacent1) and is_cell_walkable(adjacent1, floor_index) and \ #is_position_valid(adjacent2) and is_cell_walkable(adjacent2, floor_index) and \ #not is_blocked_by_obstacle(current_pos, adjacent1, 3) and \ #not is_blocked_by_obstacle(current_pos, adjacent2, 3) # #if diagonal_movement or not is_diagonal_direction(dir): #neighbors.append(NeighborInfo.new(neighbor_pos, dir, is_walkable)) # #return neighbors func get_neighbors(current_pos: Vector2i, floor_index: int) -> Array[NeighborInfo]: var neighbors: Array[NeighborInfo] = [] # Four orthogonal directions var directions = { Direction.NORTH: Vector2i(0, -1), Direction.EAST: Vector2i(1, 0), Direction.SOUTH: Vector2i(0, 1), Direction.WEST: Vector2i(-1, 0) } # Add diagonal directions if enabled if diagonal_movement: directions[Direction.NORTHWEST] = Vector2i(-1, -1) directions[Direction.NORTHEAST] = Vector2i(1, -1) directions[Direction.SOUTHWEST] = Vector2i(-1, 1) directions[Direction.SOUTHEAST] = Vector2i(1, 1) for dir in directions: var offset = directions[dir] var neighbor_pos = current_pos + offset if is_position_valid(neighbor_pos): var is_walkable = is_cell_walkable(neighbor_pos, floor_index) # Check if movement to this neighbor is blocked by obstacles if not is_diagonal_direction(dir) and is_movement_blocked(current_pos, neighbor_pos, floor_index): is_walkable = false if is_diagonal_direction(dir): # For diagonal movement, check if both orthogonal paths are blocked var mid1 = Vector2i(neighbor_pos.x, current_pos.y) var mid2 = Vector2i(current_pos.x, neighbor_pos.y) var path1_blocked = is_movement_blocked(current_pos, mid1, floor_index) var path2_blocked = is_movement_blocked(current_pos, mid2, floor_index) if path1_blocked and path2_blocked: is_walkable = false if is_walkable: neighbors.append(NeighborInfo.new(neighbor_pos, dir, is_walkable)) return neighbors # Helper functions for neighbor checking func is_diagonal_direction(direction: Direction) -> bool: return direction in [Direction.NORTHWEST, Direction.NORTHEAST, Direction.SOUTHWEST, Direction.SOUTHEAST] func is_position_valid(pos: Vector2i) -> bool: return pos.x >= 0 and pos.x < columns and pos.y >= 0 and pos.y < rows func is_cell_walkable(pos: Vector2i, floor_index: int) -> bool: var cell_item = get_cell_item(Vector3i(pos.x, floor_index, pos.y)) return cell_item != -1 and not (cell_item in non_walkable_items) # Improved A* pathfinding func initialize_astar(): astar_by_floor.clear() for y in range(floors): var astar = AStar2D.new() # Add all points for x in range(columns): for z in range(rows): var point_id = z * columns + x astar.add_point(point_id, Vector2(x, z)) # Connect points based on neighbors for x in range(columns): for z in range(rows): var current_pos = Vector2i(x, z) var current_point_id = z * columns + x if not is_cell_walkable(current_pos, y): continue var neighbors = get_neighbors(current_pos, y) for neighbor in neighbors: if neighbor.is_walkable: var neighbor_id = neighbor.position.y * columns + neighbor.position.x if not astar.are_points_connected(current_point_id, neighbor_id): var weight = 1.0 if not is_diagonal_direction(neighbor.direction) else 1.4142 # Check if movement is allowed by obstacles if not is_blocked_by_obstacle(current_pos, neighbor.position, 3): astar.connect_points(current_point_id, neighbor_id, true) astar.set_point_weight_scale(neighbor_id, weight) astar_by_floor[y] = astar update_astar_costs() func find_path(start: Vector2, end: Vector2, floor_index: int = 0, clear_path_visual: bool = true) -> Array: var astar = astar_by_floor.get(floor_index) if not astar: return [] var start_point = start.y * columns + start.x var end_point = end.y * columns + end.x path = astar.get_point_path(start_point, end_point) if clear_path_visual: clear_path_visualization(floor_index) set_cell_item(Vector3i(start.x, floor_index, start.y), start_item) set_cell_item(Vector3i(end.x, floor_index, end.y), end_item) for point in path: if point != start and point != end: set_cell_item(Vector3i(point.x, floor_index, point.y), hover_item) return path # Path visualization func clear_path_visualization(floor_index: int = 0): for x in range(columns): for z in range(rows): var cell_item = get_cell_item(Vector3i(x, floor_index, z)) if cell_item == hover_item or cell_item == start_item or cell_item == end_item: set_cell_item(Vector3i(x, floor_index, z), normal_items[0]) # Cost calculation and updates func get_cell_cost(x: int, z: int, floor_index: int = 0) -> float: var cell_item = get_cell_item(Vector3i(x, floor_index, z)) if cell_item in non_walkable_items: return INF elif cell_item == hover_item: return 0.5 elif cell_item == start_item or cell_item == end_item: return 0.0 return 1.0 func update_astar_costs(): for floor_index in range(floors): var astar = astar_by_floor.get(floor_index) if astar: for x in range(columns): for z in range(rows): var point_id = z * columns + x var cost = get_cell_cost(x, z, floor_index) if cost == INF: astar.set_point_disabled(point_id, true) else: astar.set_point_disabled(point_id, false) astar.set_point_weight_scale(point_id, cost) # Grid data management func update_grid_data(): grid_data.clear() for y in range(floors): var floor_data = [] for z in range(rows): var row = [] for x in range(columns): row.append(get_cell_item(Vector3i(x, y, z))) floor_data.append(row) grid_data.append(floor_data) emit_signal("grid_updated") # Check the obstacle on a cell func has_obstacle_at(pos: Vector3i) -> bool: var item = get_cell_item(pos) return item in obstacle_items # Get orientation ( rotation ) func get_cell_orientation(pos: Vector3i) -> int: return get_cell_item_orientation(pos) # Get obstacle direction # Get the direction of an obstacle at a specific position func get_obstacle_direction(pos: Vector3i) -> Direction: if obstacle_directions.has(pos): return obstacle_directions[pos] return Direction.CENTER #func is_movement_blocked(from_pos: Vector2i, to_pos: Vector2i, floor_index: int = 3) -> bool: ## Must be adjacent cells #if abs(from_pos.x - to_pos.x) + abs(from_pos.y - to_pos.y) != 1: #return false # ## Determine which direction we're moving #var direction: Direction # #if to_pos.y < from_pos.y: # Moving NORTH #direction = Direction.NORTH #elif to_pos.x > from_pos.x: # Moving EAST #direction = Direction.EAST #elif to_pos.y > from_pos.y: # Moving SOUTH #direction = Direction.SOUTH #elif to_pos.x < from_pos.x: # Moving WEST #direction = Direction.WEST # ## Check if the current cell has an obstacle blocking the exit #var from_obstacle_pos = Vector3i(from_pos.x, floor_index, from_pos.y) #if has_obstacle_at(from_obstacle_pos): #var obs_dir = get_obstacle_direction(from_obstacle_pos) #if obs_dir == direction: # Obstacle blocks exit in this direction #return true # ## Check if the destination cell has an obstacle blocking the entrance #var to_obstacle_pos = Vector3i(to_pos.x, floor_index, to_pos.y) #if has_obstacle_at(to_obstacle_pos): #var opposite_dir: Direction # ## Calculate the opposite direction #match direction: #Direction.NORTH: opposite_dir = Direction.SOUTH #Direction.EAST: opposite_dir = Direction.WEST #Direction.SOUTH: opposite_dir = Direction.NORTH #Direction.WEST: opposite_dir = Direction.EAST # #var obs_dir = get_obstacle_direction(to_obstacle_pos) #if obs_dir == opposite_dir: # Obstacle blocks entrance from this direction #return true # #return false func is_movement_blocked(from_pos: Vector2i, to_pos: Vector2i, floor_index: int = 3) -> bool: # Must be adjacent cells if abs(from_pos.x - to_pos.x) + abs(from_pos.y - to_pos.y) != 1: return false # Determine movement direction var direction: int if to_pos.y < from_pos.y: # Moving NORTH direction = 0 # North elif to_pos.x > from_pos.x: # Moving EAST direction = 1 # East elif to_pos.y > from_pos.y: # Moving SOUTH direction = 2 # South elif to_pos.x < from_pos.x: # Moving WEST direction = 3 # West # Check if the current cell has an obstacle blocking the exit var from_obstacle_pos = Vector3i(from_pos.x, floor_index, from_pos.y) if has_obstacle_at(from_obstacle_pos): var orientation = get_cell_orientation(from_obstacle_pos) if orientation == direction: # Obstacle blocks exit in this direction return true # Check if the destination cell has an obstacle blocking the entrance var to_obstacle_pos = Vector3i(to_pos.x, floor_index, to_pos.y) if has_obstacle_at(to_obstacle_pos): var orientation = get_cell_orientation(to_obstacle_pos) var opposite_dir = (direction + 2) % 4 # Opposite direction (0→2, 1→3, 2→0, 3→1) if orientation == opposite_dir: # Obstacle blocks entrance from this direction return true return false # Cell rotation handling func get_cell_rotation(position: Vector3i) -> int: return get_cell_item_orientation(position) func set_cell_rotation(position: Vector3i, mode: int): var item = get_cell_item(position) if item != -1: set_cell_item(position, item, mode) # Mesh library handling func _on_mesh_library_changed(): validate_item_indices() if auto_generate: generate_grid() _update_cell_option_buttons() func _update_cell_option_buttons(): if not mesh_library: return var item_list = mesh_library.get_item_list() for x in range(columns): for z in range(rows): var position = Vector3i(x, 0, z) var cell_item = get_cell_item(position) if cell_item != -1 and cell_item < item_list.size(): set_cell_item(position, cell_item) else: set_cell_item(position, 0) func _set(property, value): if property == "mesh_library": mesh_library = value _on_mesh_library_changed() return true return false # Toggle diagonal movement func set_diagonal_movement(enable: bool): diagonal_movement = enable initialize_astar() # Add this function to check if a movement is blocked by an obstacle #func is_blocked_by_obstacle(from_pos: Vector2i, to_pos: Vector2i, floor_index: int = 3) -> bool: ## Detect movement direction #var diff_x = to_pos.x - from_pos.x #var diff_y = to_pos.y - from_pos.y # ## Case 1: Moving along X axis (horizontally) #if diff_y == 0 and diff_x != 0: ## Check if there's a vertical obstacle blocking horizontal movement #var min_x = min(from_pos.x, to_pos.x) #var max_x = max(from_pos.x, to_pos.x) #for x in range(min_x, max_x + 1): #var cell_pos = Vector3i(x, floor_index, from_pos.y) #var cell_index = get_cell_item(cell_pos) #if cell_index in obstacle_items: #var obstacle_idx = obstacle_items.find(cell_index) #if obstacle_idx != -1 and obstacle_idx < obstacle_directions.size(): #var dir = obstacle_directions[obstacle_idx] #if dir == Direction.BLOCKED_NORTH or dir == Direction.BLOCKED_SOUTH: #return true # ## Case 2: Moving along Y axis (vertically) #if diff_x == 0 and diff_y != 0: ## Check if there's a horizontal obstacle blocking vertical movement #var min_y = min(from_pos.y, to_pos.y) #var max_y = max(from_pos.y, to_pos.y) #for y in range(min_y, max_y + 1): #var cell_pos = Vector3i(from_pos.x, floor_index, y) #var cell_index = get_cell_item(cell_pos) #if cell_index in obstacle_items: #var obstacle_idx = obstacle_items.find(cell_index) #if obstacle_idx != -1 and obstacle_idx < obstacle_directions.size(): #var dir = obstacle_directions[obstacle_idx] #if dir == Direction.BLOCKED_EAST or dir == Direction.BLOCKED_WEST: #return true # ## Case 3: Diagonal movement - check if both direct paths are blocked ## This will force the player to take the longer route #if diff_x != 0 and diff_y != 0: ## Check if moving horizontally first then vertically would be blocked #var horiz_first = is_blocked_by_obstacle(from_pos, Vector2i(to_pos.x, from_pos.y), floor_index) #var vert_second = is_blocked_by_obstacle(Vector2i(to_pos.x, from_pos.y), to_pos, floor_index) # ## Check if moving vertically first then horizontally would be blocked #var vert_first = is_blocked_by_obstacle(from_pos, Vector2i(from_pos.x, to_pos.y), floor_index) #var horiz_second = is_blocked_by_obstacle(Vector2i(from_pos.x, to_pos.y), to_pos, floor_index) # ## If both paths are blocked, then the diagonal movement is blocked #if (horiz_first or vert_second) and (vert_first or horiz_second): #return true # #return false #func is_blocked_by_obstacle(from_pos: Vector2i, to_pos: Vector2i, floor_index: int = 3) -> bool: ## Determine movement direction (without using normalized for Vector2i) #var diff_x = to_pos.x - from_pos.x #var diff_y = to_pos.y - from_pos.y # ## Convert to direction based on sign #var dir_x = 0 #var dir_y = 0 #if diff_x != 0: dir_x = 1 if diff_x > 0 else -1 #if diff_y != 0: dir_y = 1 if diff_y > 0 else -1 # ## Check for obstacles at both cells #var from_obstacle = get_cell_item(Vector3i(from_pos.x, floor_index, from_pos.y)) #var to_obstacle = get_cell_item(Vector3i(to_pos.x, floor_index, to_pos.y)) # ## Check obstacle at starting position #if from_obstacle in obstacle_items: #var from_pos_3d = Vector3i(from_pos.x, floor_index, from_pos.y) #var from_dir = Direction.CENTER # ## Use safe dictionary access #if obstacle_directions.has(from_pos_3d): #from_dir = obstacle_directions[from_pos_3d] # ## Block movement based on obstacle direction #match from_dir: #Direction.NORTH: # Blocks south movement #if dir_y > 0: return true #Direction.EAST: # Blocks west movement #if dir_x < 0: return true #Direction.SOUTH: # Blocks north movement #if dir_y < 0: return true #Direction.WEST: # Blocks east movement #if dir_x > 0: return true # ## Check obstacle at destination position #if to_obstacle in obstacle_items: #var to_pos_3d = Vector3i(to_pos.x, floor_index, to_pos.y) #var to_dir = Direction.CENTER # ## Use safe dictionary access #if obstacle_directions.has(to_pos_3d): #to_dir = obstacle_directions[to_pos_3d] # ## Block movement based on obstacle direction (from opposite side) #match to_dir: #Direction.NORTH: # Blocks south movement (coming from north) #if dir_y < 0: return true #Direction.EAST: # Blocks west movement (coming from east) #if dir_x > 0: return true #Direction.SOUTH: # Blocks north movement (coming from south) #if dir_y > 0: return true #Direction.WEST: # Blocks east movement (coming from west) #if dir_x < 0: return true # ## Check intermediate cell for vertical/horizontal movement #if from_pos.x != to_pos.x and from_pos.y == to_pos.y: # Horizontal movement #var x_step = 1 if to_pos.x > from_pos.x else -1 #var intermediate_x = from_pos.x + x_step #while intermediate_x != to_pos.x: #var inter_obstacle = get_cell_item(Vector3i(intermediate_x, floor_index, from_pos.y)) #if inter_obstacle in obstacle_items: #var inter_pos_3d = Vector3i(intermediate_x, floor_index, from_pos.y) #var inter_dir = Direction.CENTER # ## Use safe dictionary access #if obstacle_directions.has(inter_pos_3d): #inter_dir = obstacle_directions[inter_pos_3d] # #if inter_dir == Direction.NORTH or inter_dir == Direction.SOUTH: #return true #intermediate_x += x_step #elif from_pos.x == to_pos.x and from_pos.y != to_pos.y: # Vertical movement #var y_step = 1 if to_pos.y > from_pos.y else -1 #var intermediate_y = from_pos.y + y_step #while intermediate_y != to_pos.y: #var inter_obstacle = get_cell_item(Vector3i(from_pos.x, floor_index, intermediate_y)) #if inter_obstacle in obstacle_items: #var inter_pos_3d = Vector3i(from_pos.x, floor_index, intermediate_y) #var inter_dir = Direction.CENTER # ## Use safe dictionary access #if obstacle_directions.has(inter_pos_3d): #inter_dir = obstacle_directions[inter_pos_3d] # #if inter_dir == Direction.EAST or inter_dir == Direction.WEST: #return true #intermediate_y += y_step # ## If none of the above conditions triggered, movement is allowed #return false # Updated is_blocked_by_obstacle to check for each step in the path func is_blocked_by_obstacle(from_pos: Vector2i, to_pos: Vector2i, floor_index: int = 3) -> bool: # For orthogonal movement (up, down, left, right) if from_pos.x == to_pos.x or from_pos.y == to_pos.y: # Check each step along the path var dx = sign(to_pos.x - from_pos.x) var dy = sign(to_pos.y - from_pos.y) var current = from_pos while current != to_pos: var next = Vector2i(current.x + dx, current.y + dy) if is_movement_blocked(current, next, floor_index): return true current = next else: # For diagonal movement, check if both orthogonal paths are blocked var mid1 = Vector2i(to_pos.x, from_pos.y) var mid2 = Vector2i(from_pos.x, to_pos.y) var path1_blocked = is_blocked_by_obstacle(from_pos, mid1, floor_index) var path2_blocked = is_blocked_by_obstacle(from_pos, mid2, floor_index) return path1_blocked and path2_blocked return false #func place_obstacle(pos: Vector3i, obstacle_item: int, direction: Direction) -> bool: ## Always place on floor 3 #pos.y = 3 # #if get_cell_item(pos) != -1: #return false # Cell is already occupied # #set_cell_item(pos, obstacle_item) # ## Store the direction of the obstacle in the dictionary #obstacle_directions[pos] = direction # ## Update the cell's orientation based on direction #var orientation = 0 #match direction: #Direction.NORTH: #orientation = 0 # Default orientation #Direction.EAST: #orientation = 1 # 90 degrees clockwise #Direction.SOUTH: #orientation = 2 # 180 degrees #Direction.WEST: #orientation = 3 # 270 degrees clockwise # #set_cell_item(pos, obstacle_item, orientation) # ## Re-initialize A* pathfinding to account for the new obstacle #initialize_astar() # #return true func place_obstacle(pos: Vector3i, obstacle_item: int, orientation: int) -> bool: # Always place on floor 3 pos.y = 3 if get_cell_item(pos) != -1: return false # Cell is already occupied # Set the obstacle item with the specified orientation set_cell_item(pos, obstacle_item, orientation) # Re-initialize A* pathfinding to account for the new obstacle initialize_astar() return true