fix walking with pots /pushing into walls etc

This commit is contained in:
2025-12-26 09:04:26 +01:00
parent 93059d12de
commit def119e21d
2 changed files with 105 additions and 12 deletions

View File

@@ -288,7 +288,77 @@ func _physics_process(delta: float) -> void:
# Sync invulnerability cleared to clients
if multiplayer.is_server():
sync_invulnerability.rpc(false)
move_and_collide(velocity * delta)
# Check for collisions to prevent pushing ungrabed objects
# Handle diagonal movement: try moving in each direction separately to allow sliding
var movement = velocity * delta
if movement.length() > 0:
# Store original position to test both directions from the same starting point
var original_position = global_position
var allowed_movement = Vector2.ZERO
# Test X movement
if abs(movement.x) > 0.01:
var x_movement = Vector2(movement.x, 0)
var collision_x = move_and_collide(x_movement)
var x_actual_movement = global_position - original_position
if collision_x:
var collider_x = collision_x.get_collider()
if collider_x != null:
var is_pot_x = "is_being_grabbed" in collider_x or "is_being_lifted" in collider_x
var is_player_x = "is_player" in collider_x and collider_x.is_player
# If it's an ungrabed pot/player, move back and don't allow X movement
if ((is_pot_x and not collider_x.is_being_grabbed and not collider_x.is_being_lifted) or (is_player_x and collider_x != self)):
if not (grabbed_entity == collider_x or held_entity == collider_x):
# Move back to original position
global_position = original_position
allowed_movement.x = 0
else:
# We're grabbing it, allow the movement
allowed_movement.x = x_actual_movement.x
else:
# It's a wall - use the actual movement (move_and_collide handled sliding)
allowed_movement.x = x_actual_movement.x
else:
# No collision, X movement succeeded
allowed_movement.x = x_actual_movement.x
# Reset to original position for Y test
global_position = original_position
# Test Y movement
if abs(movement.y) > 0.01:
var y_movement = Vector2(0, movement.y)
var collision_y = move_and_collide(y_movement)
var y_actual_movement = global_position - original_position
if collision_y:
var collider_y = collision_y.get_collider()
if collider_y != null:
var is_pot_y = "is_being_grabbed" in collider_y or "is_being_lifted" in collider_y
var is_player_y = "is_player" in collider_y and collider_y.is_player
# If it's an ungrabed pot/player, move back and don't allow Y movement
if ((is_pot_y and not collider_y.is_being_grabbed and not collider_y.is_being_lifted) or (is_player_y and collider_y != self)):
if not (grabbed_entity == collider_y or held_entity == collider_y):
# Move back to original position
global_position = original_position
allowed_movement.y = 0
else:
# We're grabbing it, allow the movement
allowed_movement.y = y_actual_movement.y
else:
# It's a wall - use the actual movement (move_and_collide handled sliding)
allowed_movement.y = y_actual_movement.y
else:
# No collision, Y movement succeeded
allowed_movement.y = y_actual_movement.y
# Reset to original position
global_position = original_position
# Apply the combined allowed movement
if allowed_movement.length() > 0.01:
move_and_collide(allowed_movement)
else:
# Client also needs to decrement knockback_timer for visual effects
if knockback_timer > 0:

View File

@@ -226,6 +226,8 @@ func _physics_process(delta: float) -> void:
if "locked_grab_direction" in holder and holder.locked_grab_direction != Vector2.ZERO:
locked_dir = holder.locked_grab_direction.normalized()
# Calculate desired movement based on push/pull
var desired_movement = Vector2.ZERO
if locked_dir != Vector2.ZERO:
# Project player's movement onto the push/pull direction
var movement_along_axis = player_movement.project(locked_dir)
@@ -236,18 +238,41 @@ func _physics_process(delta: float) -> void:
if is_pushing:
# PUSHING: Pot moves first, ahead of player
# Move pot by slightly more than player movement so it leads (moves first)
var push_movement = movement_along_axis * push_lead_factor
global_position += push_movement
velocity = push_movement / delta if delta > 0 else Vector2.ZERO
desired_movement = movement_along_axis * push_lead_factor
else:
# PULLING: Player moves first, pot follows behind
# Move pot by the exact same amount as player (pot follows immediately)
global_position += movement_along_axis
velocity = movement_along_axis / delta if delta > 0 else Vector2.ZERO
desired_movement = movement_along_axis
else:
# No locked direction, just move pot by player's movement
global_position += player_movement
velocity = player_movement / delta if delta > 0 else Vector2.ZERO
desired_movement = player_movement
# Check for collisions before moving - use space query to test
var space_state = get_world_2d().direct_space_state
var query = PhysicsShapeQueryParameters2D.new()
query.shape = $CollisionShape2D.shape
query.transform = global_transform.translated(desired_movement)
query.collision_mask = collision_mask
query.exclude = [self, holder] # Exclude self and holder from query
var results = space_state.intersect_shape(query, 1)
var can_move = true
# Check if any collision would block movement
for result in results:
var collider = result.collider
if collider != null:
# If it's a wall, another pot, or another player, block movement
can_move = false
break
if can_move:
# No blocking collision - move the pot
global_position += desired_movement
velocity = desired_movement / delta if delta > 0 else Vector2.ZERO
else:
# Something is blocking - don't move the pot
velocity = Vector2.ZERO
# Update previous position for next frame
previous_holder_position = holder.global_position
@@ -568,10 +593,8 @@ func grab(new_holder: CharacterBody2D) -> bool:
# Initialize previous position to current position so we can track movement
previous_holder_position = new_holder.global_position
previous_client_position = global_position # Initialize client position tracking
# Disable pot's collision layer so grabber can't collide with it (prevents blocking when pushing)
# Note: This also means other players can't collide with pot while it's grabbed
# The pot uses direct position updates (not move_and_collide) so collisions aren't needed for movement
self.set_collision_layer_value(8, false) # Disable pot's collision layer
# Keep pot's collision enabled so it can collide with other players while being pushed/pulled
# The pot uses direct position updates (not move_and_collide) but still needs collision for other players
# Don't change pot's position - it should stay where it is and only move when player pushes/pulls
return true
return false