update obstacles

This commit is contained in:
2025-03-11 17:40:54 +08:00
parent 495c9c64a5
commit 161f03d931
3 changed files with 225 additions and 50 deletions
+152 -27
View File
@@ -267,6 +267,56 @@ func randomize_floor_custom(randomize_states: Array, floor_index: int):
set_cell_item(cell_pos, normal_items[0], current_orientation) set_cell_item(cell_pos, normal_items[0], current_orientation)
# Improved neighbor checking system # 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]: func get_neighbors(current_pos: Vector2i, floor_index: int) -> Array[NeighborInfo]:
var neighbors: 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): if is_position_valid(neighbor_pos):
var is_walkable = is_cell_walkable(neighbor_pos, floor_index) 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): if is_diagonal_direction(dir):
var adjacent1: Vector2i var adjacent1: Vector2i
var adjacent2: Vector2i var adjacent2: Vector2i
match dir: match dir:
Direction.NORTHWEST: Direction.NORTHWEST:
adjacent1 = current_pos + Vector2i(-1, 0) adjacent1 = current_pos + Vector2i(-1, 0) # West
adjacent2 = current_pos + Vector2i(0, -1) adjacent2 = current_pos + Vector2i(0, -1) # North
Direction.NORTHEAST: Direction.NORTHEAST:
adjacent1 = current_pos + Vector2i(1, 0) adjacent1 = current_pos + Vector2i(1, 0) # East
adjacent2 = current_pos + Vector2i(0, -1) adjacent2 = current_pos + Vector2i(0, -1) # North
Direction.SOUTHWEST: Direction.SOUTHWEST:
adjacent1 = current_pos + Vector2i(-1, 0) adjacent1 = current_pos + Vector2i(-1, 0) # West
adjacent2 = current_pos + Vector2i(0, 1) adjacent2 = current_pos + Vector2i(0, 1) # South
Direction.SOUTHEAST: Direction.SOUTHEAST:
adjacent1 = current_pos + Vector2i(1, 0) adjacent1 = current_pos + Vector2i(1, 0) # East
adjacent2 = current_pos + Vector2i(0, 1) 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_walkable = is_walkable and \
is_position_valid(adjacent1) and is_cell_walkable(adjacent1, floor_index) 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 \ 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, adjacent1, 3) and \
not is_blocked_by_obstacle(current_pos, adjacent2, floor_index) not is_blocked_by_obstacle(current_pos, adjacent2, 3)
if diagonal_movement or not is_diagonal_direction(dir): if diagonal_movement or not is_diagonal_direction(dir):
neighbors.append(NeighborInfo.new(neighbor_pos, dir, is_walkable)) 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): 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 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 astar_by_floor[y] = astar
@@ -474,35 +534,100 @@ func set_diagonal_movement(enable: bool):
initialize_astar() initialize_astar()
# Add this function to check if a movement is blocked by an obstacle # 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: #func is_blocked_by_obstacle(from_pos: Vector2i, to_pos: Vector2i, floor_index: int = 3) -> bool:
# Check if there's a horizontal obstacle ## Detect movement direction
if from_pos.y == to_pos.y: # Moving horizontally #var diff_x = to_pos.x - from_pos.x
# Check for vertical obstacles that would block horizontal movement #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 min_x = min(from_pos.x, to_pos.x)
var max_x = max(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): for x in range(min_x, max_x):
var cell_index = get_cell_item(Vector3i(x, floor_index, from_pos.y)) var cell_pos = Vector3i(x, floor_index, from_pos.y)
var cell_index = get_cell_item(cell_pos)
if cell_index in obstacle_items: if cell_index in obstacle_items:
var obstacle_idx = obstacle_items.find(cell_index) 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] var dir = obstacle_directions[obstacle_idx]
if dir == Direction.BLOCKED_NORTH or dir == Direction.BLOCKED_SOUTH: if dir == Direction.BLOCKED_NORTH or dir == Direction.BLOCKED_SOUTH:
return true return true
# Check if there's a vertical obstacle # Simple case: Moving vertically (same X)
if from_pos.x == to_pos.x: # Moving vertically if from_pos.x == to_pos.x:
# Check for horizontal obstacles that would block vertical movement # Check for horizontal obstacles that block vertical movement
var min_y = min(from_pos.y, to_pos.y) var min_y = min(from_pos.y, to_pos.y)
var max_y = max(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): for y in range(min_y, max_y):
var cell_index = get_cell_item(Vector3i(from_pos.x, floor_index, 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: if cell_index in obstacle_items:
var obstacle_idx = obstacle_items.find(cell_index) 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] var dir = obstacle_directions[obstacle_idx]
if dir == Direction.BLOCKED_EAST or dir == Direction.BLOCKED_WEST: if dir == Direction.BLOCKED_EAST or dir == Direction.BLOCKED_WEST:
return true 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 return false
func place_obstacle(pos: Vector3i, obstacle_item: int, direction: Direction) -> bool: func place_obstacle(pos: Vector3i, obstacle_item: int, direction: Direction) -> bool:
+3
View File
@@ -249,6 +249,9 @@ func place_obstacle(grid_position: Vector2i):
# Don't exit the obstacle placement mode to allow multiple placements # Don't exit the obstacle placement mode to allow multiple placements
local_player_character.highlight_valid_obstacle_cells() 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 # Sync the obstacle with other clients
if is_multiplayer_authority(): if is_multiplayer_authority():
rpc("sync_place_obstacle", grid_position.x, grid_position.y, floor_index, current_obstacle_item, direction) rpc("sync_place_obstacle", grid_position.x, grid_position.y, floor_index, current_obstacle_item, direction)
+70 -23
View File
@@ -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) distance = abs(target_position.x - current_position.x) + abs(target_position.y - current_position.y)
return distance <= movement_range 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): func move_player_to_clicked_position(grid_position: Vector2i):
if not is_multiplayer_authority() or is_player_moving or action_points <= 0: if not is_multiplayer_authority() or is_player_moving or action_points <= 0:
return 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): if cell_item in enhanced_gridmap.non_walkable_items or is_position_occupied(grid_position):
return 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) rotate_towards_target(grid_position)
var path = enhanced_gridmap.find_path(Vector2(current_position), Vector2(grid_position)) # Create a direct path rather than using A* for obstacle avoidance
if path.size() <= 1: # This ensures the player can only move to directly accessible positions
return var path = [Vector2(current_position.x, current_position.y), Vector2(grid_position.x, grid_position.y)]
path.pop_front()
var valid_path = true
for point in path.slice(1): rpc("start_movement_along_path", path, not (is_bot or is_in_group("Bots")))
if is_position_occupied(Vector2i(point.x, point.y)): action_points -= 1
valid_path = false
break # Clear highlights after moving
if not (is_bot or is_in_group("Bots")):
if valid_path: clear_highlights()
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")
@rpc("any_peer", "call_local") @rpc("any_peer", "call_local")
func start_movement_along_path(path: Array, clear_visual: bool = true): func start_movement_along_path(path: Array, clear_visual: bool = true):
@@ -815,13 +850,25 @@ func highlight_movement_range():
return return
var cells_to_highlight = [] var cells_to_highlight = []
# Only highlight cells within movement range that aren't blocked by obstacles
for x in range(enhanced_gridmap.columns): for x in range(enhanced_gridmap.columns):
for z in range(enhanced_gridmap.rows): for z in range(enhanced_gridmap.rows):
var test_pos = Vector2i(x, z) 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): if is_within_movement_range(test_pos):
var cell_item = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) 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): 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) highlight_cells_if_authorized(cells_to_highlight)
@@ -976,7 +1023,7 @@ func clear_highlights():
child.hide() child.hide()
# Restore highlights based on current action state # 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() highlight_movement_range()
func clear_playerboard_highlights(): func clear_playerboard_highlights():