diff --git a/src/scripts/entities/player/player.gd b/src/scripts/entities/player/player.gd index 044aa18..a375570 100644 --- a/src/scripts/entities/player/player.gd +++ b/src/scripts/entities/player/player.gd @@ -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: diff --git a/src/scripts/entities/world/pot.gd b/src/scripts/entities/world/pot.gd index d7b08e7..d5a6a0f 100644 --- a/src/scripts/entities/world/pot.gd +++ b/src/scripts/entities/world/pot.gd @@ -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