VERY weird sliding behavior when CharacterBody2d hits a corner

Godot Version

v4.2.2.stable.official [15073afe3]

Information

The behavior is hard for me to explain in words, so I’ll attach a video as well as try to describe it.

I have a CharacterBody2D with a CollisionShape2D circle as a character. I also have a StaticBody2D with a few CollisionShape2Ds as a level.

The character is coded to launch itself in the direction of the mouse when hitting the button; it just adds velocity in that direction on the moment the button is pressed. There’s a bunch of code, but I tested with nothing but the few lines needed for that and the behavior still happens.

The Behavior

When hitting a corner (the hard edge of a CollisionShape2D rectangle, or the rounded end of a CollisionShape2D capsule shape), the player slowly slides along the corner or the curve until it eventually stops, at a seemingly random point.

With the basic code, the velocity remains unchanged as this happens, which is what normally happens in a collision between a CharacterBody2D and a StaticBody2D.
However, I have a bit of code that sets the velocity to (0, 0) when is_on_wall() returns true (Motion Mode is set to floating, so everything counts as a wall):

Using print(velocity) and print(get_real_velocity()) I can see that, even while the character is doing the weird slide, the velocity is 0. The “real velocity” isn’t 0, but that’s not as weird to me as the character moving while the velocity is (0, 0).

Additionally, the slide will happen in a direction I don’t know how to predict. The character can be moving up and to the right when it hits the corner, and slide down and to the left.

I was not able to replicate this when setting the CharacterBody2D’s CollisionShape2D to a square or to a capsule.

The Code

I tested with nothing but this code running, and the problem persisted:

const SPEED = 1200
var mouse_position = null

func _physics_process(delta):
	mouse_position = get_global_mouse_position()
	var direction = (mouse_position - self.position).normalized()

	if Input.is_action_just_pressed("up") and get_real_velocity() == Vector2.ZERO:
		velocity = direction * SPEED

	move_and_slide()

The Video

In the video, the only thing I was doing was moving the mouse, and pressing (and releasing) “W”:

(the raycasts are just there for testing and debugging, to be clear)

This is my first ever game I am trying to make, please do let me know if there’s something I’m visibly doing wrong that’s causing this. To me it seems like a bug with the engine, but being so new to it, I really can’t know that for sure.

Thanks!

It sounds like the sliding issue happens due to how “move_and_slide()” handles collisions, especially at corners or curved surfaces. Even when your velocity is set to “(0, 0)”, the engine may still try to resolve the collision by sliding the character slightly.

To address this, you can try manually handling collisions using “move_and_collide()” instead of relying solely on “move_and_slide()”. This gives you more control over how the character reacts at corners.

Here’s a quick example:

const SPEED = 1200
var mouse_position = null

func _physics_process(delta):
    mouse_position = get_global_mouse_position()
    var direction = (mouse_position - self.position).normalized()

    if Input.is_action_just_pressed("up") and get_real_velocity() == Vector2.ZERO:
        velocity = direction * SPEED
    
    var collision_info = move_and_collide(velocity * delta)

    if collision_info:
        var collision_normal = collision_info.normal
        if abs(collision_normal.x) > 0.9 and abs(collision_normal.y) > 0.9:
            velocity = Vector2.ZERO  # Stop at corners
        else:
            move_and_slide()

This code checks for corner collisions and stops the character if one is detected. You might need to adjust it based on your specific needs. Also, make sure your physics layers and masks are set up correctly to avoid unintended interactions.

1 Like

I did forget to mention the important detail that I did try move_and_collide(velocity* delta), but I didn’t change anything else in the code. Detecting the corner and manually setting velocity to 0 might work, thanks!

I won’t be at my computer for most of today, I’ll try it out when I get the chance

1 Like

If “move_and_collide(velocity * delta)” didn’t solve it, detecting corners and manually setting the velocity to zero should probably help,

lemme know how it went :neutral_face:

1 Like

Went through a bunch of stuff trying to get it working. Changed a bunch of the code in the process, which ended up simplifying a bunch of it, so that’s nice. Ultimately I managed to detect corners doing some stuff with raycasts, but afterwards I realized I don’t need to do that.

The answer was as simple as only calling move_and_collide() if the velocity is not 0 (and some other code, but that’s less important).

It would’ve taken me ages to get there without your help, if I got there at all lol, so thanks!

1 Like

Why did you mark yourself as solution ? :neutral_face:

1 Like

Because the solution was in my message

If the custom here is to mark the most helpful response even if it’s not the actual solution, my bad :sweat_smile:, let me know and I’ll change it

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.