diff --git a/addons/enhanced_gridmap/enhanced_gridmap.gd b/addons/enhanced_gridmap/enhanced_gridmap.gd index b16ea19..7215e0b 100644 --- a/addons/enhanced_gridmap/enhanced_gridmap.gd +++ b/addons/enhanced_gridmap/enhanced_gridmap.gd @@ -267,6 +267,56 @@ func randomize_floor_custom(randomize_states: Array, floor_index: int): set_cell_item(cell_pos, normal_items[0], current_orientation) # Improved neighbor checking system +#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) + # + #if is_diagonal_direction(dir): + #var adjacent1: Vector2i + #var adjacent2: Vector2i + # + #match dir: + #Direction.NORTHWEST: + #adjacent1 = current_pos + Vector2i(-1, 0) + #adjacent2 = current_pos + Vector2i(0, -1) + #Direction.NORTHEAST: + #adjacent1 = current_pos + Vector2i(1, 0) + #adjacent2 = current_pos + Vector2i(0, -1) + #Direction.SOUTHWEST: + #adjacent1 = current_pos + Vector2i(-1, 0) + #adjacent2 = current_pos + Vector2i(0, 1) + #Direction.SOUTHEAST: + #adjacent1 = current_pos + Vector2i(1, 0) + #adjacent2 = current_pos + Vector2i(0, 1) + # + #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, floor_index) and \ + #not is_blocked_by_obstacle(current_pos, adjacent2, floor_index) + # + #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] = [] @@ -288,29 +338,36 @@ func get_neighbors(current_pos: Vector2i, floor_index: int) -> Array[NeighborInf 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) - adjacent2 = current_pos + Vector2i(0, -1) + adjacent1 = current_pos + Vector2i(-1, 0) # West + adjacent2 = current_pos + Vector2i(0, -1) # North Direction.NORTHEAST: - adjacent1 = current_pos + Vector2i(1, 0) - adjacent2 = current_pos + Vector2i(0, -1) + adjacent1 = current_pos + Vector2i(1, 0) # East + adjacent2 = current_pos + Vector2i(0, -1) # North Direction.SOUTHWEST: - adjacent1 = current_pos + Vector2i(-1, 0) - adjacent2 = current_pos + Vector2i(0, 1) + adjacent1 = current_pos + Vector2i(-1, 0) # West + adjacent2 = current_pos + Vector2i(0, 1) # South Direction.SOUTHEAST: - adjacent1 = current_pos + Vector2i(1, 0) - adjacent2 = current_pos + Vector2i(0, 1) + 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, floor_index) and \ - not is_blocked_by_obstacle(current_pos, adjacent2, floor_index) + 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)) @@ -357,8 +414,11 @@ func initialize_astar(): 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 - astar.connect_points(current_point_id, neighbor_id, true) - astar.set_point_weight_scale(neighbor_id, weight) + + # 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 @@ -474,35 +534,100 @@ func set_diagonal_movement(enable: bool): 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 = 0) -> bool: - # Check if there's a horizontal obstacle - if from_pos.y == to_pos.y: # Moving horizontally - # Check for vertical obstacles that would block horizontal movement +#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: + # Simple case: Moving horizontally (same Y) + if from_pos.y == to_pos.y: + # Check for vertical obstacles that block 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_index = get_cell_item(Vector3i(x, floor_index, from_pos.y)) + for x in range(min_x, max_x): + 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(): + if obstacle_idx != -1 and obstacle_directions.size() > obstacle_idx: var dir = obstacle_directions[obstacle_idx] if dir == Direction.BLOCKED_NORTH or dir == Direction.BLOCKED_SOUTH: return true - # Check if there's a vertical obstacle - if from_pos.x == to_pos.x: # Moving vertically - # Check for horizontal obstacles that would block vertical movement + # Simple case: Moving vertically (same X) + if from_pos.x == to_pos.x: + # Check for horizontal obstacles that block 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_index = get_cell_item(Vector3i(from_pos.x, floor_index, y)) + for y in range(min_y, max_y): + 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(): + if obstacle_idx != -1 and obstacle_directions.size() > obstacle_idx: var dir = obstacle_directions[obstacle_idx] if dir == Direction.BLOCKED_EAST or dir == Direction.BLOCKED_WEST: return true + # For diagonal movement, if direct path is blocked, return true + # This ensures diagonal moves across obstacles aren't allowed + if from_pos.x != to_pos.x and from_pos.y != to_pos.y: + # Check if horizontal movement would be blocked + if is_blocked_by_obstacle(from_pos, Vector2i(to_pos.x, from_pos.y), floor_index): + return true + + # Check if vertical movement would be blocked + if is_blocked_by_obstacle(Vector2i(from_pos.x, to_pos.y), to_pos, floor_index): + return true + return false func place_obstacle(pos: Vector3i, obstacle_item: int, direction: Direction) -> bool: diff --git a/scenes/main.gd b/scenes/main.gd index 6f0fb74..68ef3e5 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -249,6 +249,9 @@ func place_obstacle(grid_position: Vector2i): # Don't exit the obstacle placement mode to allow multiple placements local_player_character.highlight_valid_obstacle_cells() + # Exit obstacle placement mode and return to default state + set_action_state(ActionState.NONE) + # Sync the obstacle with other clients if is_multiplayer_authority(): rpc("sync_place_obstacle", grid_position.x, grid_position.y, floor_index, current_obstacle_item, direction) diff --git a/scenes/player.gd b/scenes/player.gd index d1d8977..f57b3d4 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -297,6 +297,45 @@ func is_within_movement_range(target_position: Vector2i) -> bool: distance = abs(target_position.x - current_position.x) + abs(target_position.y - current_position.y) return distance <= movement_range +#func move_player_to_clicked_position(grid_position: Vector2i): + #if not is_multiplayer_authority() or is_player_moving or action_points <= 0: + #return + # + #var main = get_tree().get_root().get_node_or_null("Main") + #if not main or main.current_action_state != main.ActionState.MOVING or not grid_position in highlighted_cells: + #return +# + #if not is_within_movement_range(grid_position): + #return +# + #var cell_item = enhanced_gridmap.get_cell_item(Vector3i(grid_position.x, 0, grid_position.y)) + #if cell_item in enhanced_gridmap.non_walkable_items or is_position_occupied(grid_position): + #return +# + #rotate_towards_target(grid_position) +# + #var path = enhanced_gridmap.find_path(Vector2(current_position), Vector2(grid_position)) + #if path.size() <= 1: + #return +# + #var valid_path = true + #for point in path.slice(1): + #if is_position_occupied(Vector2i(point.x, point.y)): + #valid_path = false + #break +# + #if valid_path: + #path.pop_front() + ## Pass clear_visual=false for bots to preserve player highlights + #rpc("start_movement_along_path", path, not (is_bot or is_in_group("Bots"))) + #action_points -= 1 + # + ## Only clear highlights if not a bot + #if not (is_bot or is_in_group("Bots")): + #clear_highlights() + #else: + #print("Path is blocked by other players") + func move_player_to_clicked_position(grid_position: Vector2i): if not is_multiplayer_authority() or is_player_moving or action_points <= 0: return @@ -312,29 +351,25 @@ func move_player_to_clicked_position(grid_position: Vector2i): if cell_item in enhanced_gridmap.non_walkable_items or is_position_occupied(grid_position): return + # Check if direct movement is blocked by an obstacle + if enhanced_gridmap.is_blocked_by_obstacle(current_position, grid_position, 3): + # Do not allow movement if blocked (this should not happen if highlight logic is correct) + print("Movement blocked by obstacle") + return + rotate_towards_target(grid_position) - var path = enhanced_gridmap.find_path(Vector2(current_position), Vector2(grid_position)) - if path.size() <= 1: - return - - var valid_path = true - for point in path.slice(1): - if is_position_occupied(Vector2i(point.x, point.y)): - valid_path = false - break - - if valid_path: - path.pop_front() - # Pass clear_visual=false for bots to preserve player highlights - rpc("start_movement_along_path", path, not (is_bot or is_in_group("Bots"))) - action_points -= 1 - - # Only clear highlights if not a bot - if not (is_bot or is_in_group("Bots")): - clear_highlights() - else: - print("Path is blocked by other players") + # Create a direct path rather than using A* for obstacle avoidance + # This ensures the player can only move to directly accessible positions + var path = [Vector2(current_position.x, current_position.y), Vector2(grid_position.x, grid_position.y)] + path.pop_front() + + rpc("start_movement_along_path", path, not (is_bot or is_in_group("Bots"))) + action_points -= 1 + + # Clear highlights after moving + if not (is_bot or is_in_group("Bots")): + clear_highlights() @rpc("any_peer", "call_local") func start_movement_along_path(path: Array, clear_visual: bool = true): @@ -815,13 +850,25 @@ func highlight_movement_range(): return var cells_to_highlight = [] + + # Only highlight cells within movement range that aren't blocked by obstacles for x in range(enhanced_gridmap.columns): for z in range(enhanced_gridmap.rows): var test_pos = Vector2i(x, z) + + # Skip the current position + if test_pos == current_position: + continue + + # Check if within movement range if is_within_movement_range(test_pos): var cell_item = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) + + # Check if cell is walkable and not occupied if cell_item != -1 and not (cell_item in enhanced_gridmap.non_walkable_items) and not is_position_occupied(test_pos): - cells_to_highlight.append(test_pos) + # Most importantly, check if movement is blocked by obstacles + if not enhanced_gridmap.is_blocked_by_obstacle(current_position, test_pos, 3): + cells_to_highlight.append(test_pos) highlight_cells_if_authorized(cells_to_highlight) @@ -976,7 +1023,7 @@ func clear_highlights(): child.hide() # Restore highlights based on current action state - if main and current_state == main.ActionState.MOVING and is_my_turn: + if main and current_state == main.ActionState.MOVING and is_my_turn and current_state != main.ActionState.PLACING_OBSTACLE: highlight_movement_range() func clear_playerboard_highlights():