When a moving wall pushes the player, using move_and_slide() prevents the player from moving away from the wall — they just slide along its surface.
Example:
The wall moves right at 100 px/s. Once it contacts the player, the player inputs right at 200 px/s. I expect the player to actually move right at 200 px/s and break away from the wall, but instead they just keep sliding along the wall.
Increasing the player’s safe_margin works for low wall speeds — the player can break away. But at higher wall speeds, the collision still prevents separation (the wall’s velocity overcomes the safe margin). Also, a large safe margin causes noticeable jitter when the player collides with a static wall.
Is there a better way to solve this? Do I need to rewrite it with move_and_collide()?
# Scene
func _physics_process(delta: float) -> void:
$StaticBody2D.global_position.x += 100.0 * delta
# Player
var speed: float = 800.0
func _physics_process(delta):
var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down")
velocity = input_dir * speed
move_and_slide()
It’s a top-down 2D situation, player moves on a flat horizontal plane, a moving wall pushes the player, but when the player tries to move faster in the same direction, they get stuck instead of breaking away.
You might have better luck if you use a CharacterBody2D for your moving platform instead of a StaticBody2D. StaticBodies don’t actually move when you program them to do so, they calculate where they should be then teleport to the new location with no physics interaction. This could be what’s causing the issues with your physics.
Also, if the block and the player are moving at the same speed, there’s nothing in your code to add the velocity of the block to the velocity of the player. The player’s movement code is just velocity = input_dir * speed and this will always be 800 no matter what affects the player.
To reiterate, what you need to do is use a CharacterBody2D for your moving wall, and add its velocity to the player’s in code.
I changed the code to this, the problem still exists. When the wall contacts the player, I input Key D to move right, player node can’t move right at 800px/s. Player can only slide along the wall
The reason I asked is I was wondering whether you might be calling move_and_slide() on the player more than once, and if you had any other scripts in the scene.
Also, I wanted to recreate your scene in Godot and test some things out. Give me a few.
Then I recreated your code, and it worked fine as well.
extends Node2D
var player_speed: float = 300.0
var wall_speed: float = 100.0
@onready var wall: AnimatableBody2D = $AnimatableBody2D
@onready var player: CharacterBody2D = $CharacterBody2D
func _physics_process(delta: float) -> void:
var input_dir: Vector2 = Input.get_vector("move_left", "move_right", "move_up", "move_down")
player.velocity = input_dir * player_speed
player.move_and_slide()
wall.global_position.x += wall_speed * delta
When I copied your code into Godot however, all the actions ("move_left", "move_right", "move_up", "move_down") were using smart quotes instead of normal quotes, and I got an error from Godot. Are you getting this error?
Either way, copying and pasting my code should solve your problem.
Sorry, I missed one detail: my player’s collision shape is a CircleShape2D. I just tested it with a RectangleShape2D, and indeed there was no problem. It might be caused by the collision shape being a CircleShape2D.
When I copied the code back into Godot, I also encountered issues with quotation marks. It might have been a mistake during copying to the web page. I’ve already corrected all the quotation marks in Godot. It won’t affect the result.
It appears that if the CollisionShape2D is only a pixel in size on the colliding side, it cannot break away. That should probably be logged as a bug here: Godot Issues
One solution is to make a CapsuleShape2D and make it round, then add a half pixel to the height.