Godot: Kinematicbody snap drags objects down even without any velocity

Created on 21 Sep 2018  路  24Comments  路  Source: godotengine/godot

Godot version 534b7ef

Kinematicbody snap drags objects down even without any velocity.

This is 3D, it is just sideview to better illustrate what is happening.
snap_drag

This is the full code in kinematicbody.

extends KinematicBody

var vel = Vector3()

func _physics_process(delta):
    vel = move_and_slide_with_snap(vel, Vector3(0, -1, 0), Vector3(0, 1, 0))

Copied here from one of my comments for visibility:

Increasing collision safe margin makes it go faster so I think something like this happens:
Kinematicbody snaps straight down to floor, then separates to safe margin along collision normal.
Since collision normal is not parallel to y axis it moves slightly sideways and then this repeats.

Minimal Project.zip

bug physics

Most helpful comment

The solution to this for now probably would be to not use snap if your character is not actually moving left or right (or use a threshold). I'm not quite sure this is a bug yet, but I plan to rewrite both KinematicBodies (2D and 3D) for 4.0 into a way where these things can be customized more. I will kick to then.

All 24 comments

You think this is a bug?
stop_on_slopeis set to false by default

Yes. There is no velocity applied to the kinematicbody so it shouldn't move.
And as you can see the ball stops at the end of the surface, because at that point collision normal's angle to floor_normal is higher than floor_max_angle and snapping stops.

it will always slide down any slope if stop_on_slopeis set to false.

Remember you're dealing with 3.1 and it has gone through a bunch of undocumented changes. You can't expect it to work exactly like 3.0.

preview

No, kinematicbody doesn't move anywhere if you don't move it.

Increasing collision safe margin makes it go faster so I think something like this happens:
Kinematicbody snaps straight down to floor, then separates to safe margin along collision normal.
Since collision normal is not parallel to y axis it moves slightly sideways and then this repeats.

it will always slide down any slope if stop_on_slopeis set to false.

Remember you're dealing with 3.1 and it has gone through a bunch of undocumented changes. You can't expect it to work exactly like 3.0.

Are you seriously suggesting that it would just magically move?
The only reason it currently moves in the provided minimal project is because the ball starts slightly inside the surface. This collision activates the snapping. If you try moving the ball out of the surface and then running the project the ball will stay still in the air, because there is nothing in the script that is moving it.

And I just noticed that stop_on_slope is broken on 3D too and slows down the sliding speed when moving uphill.

Yeah it seems like a bug indeed. I'm not claiming anything happens magically but it's clear that the change from slope_min_velocity to stope_on_slope wasn't well tested.

Ah, it's the snapping force pulling you downhill. Try setting it to a positive value and you'll see that you don't slide at all.

Ah, it's the snapping force pulling you downhill.

If you read the current docs, the vector is just a simple vector (no magical powers involved):


Vector3 move_and_slide_with_snap( Vector3 linear_velocity, Vector3 snap, Vector3 floor_normal=Vector3( 0, 0, 0 ), bool infinite_inertia=true, bool stop_on_slope=false, int max_bounces=4, float floor_max_angle=0.785398 )

Moves the body while keeping it attached to slopes. Similar to move_and_slide().

As long as the snap vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by settingsnap to(0, 0, 0) or by using move_and_slide() instead. 芦

Ah, it's the snapping force pulling you downhill.

If you read the current docs, the vector is just a simple vector (no magical powers involved):

禄 As long as the snap vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by settingsnap to(0, 0, 0) or by using move_and_slide() instead. 芦

Well then the vector is pulling the kinematic body straight down on the Y axis (-1) so I suppose it's working like gravity. The surface is sloped too so the body will slide down.

Well then the vector is pulling the kinematic body straight down on the Y axis (-1) so I suppose it's working like gravity. The surface is sloped too so the body will slide down.

If the method description is correct, the vector shouldn't represent a force. It selects the surface to which the body should be attached. How well it has been implemented is another question. It looks as if it only works as intended if the snap vector is in the opposite direction to the collision normal?

Not in a place to share my project but,

Changing from 3.0 to 3.1 has affected my player movement and he will now slide down slopes. This is a slight improvement for me but still not perfect.

I will agree that stop_on_slope is messed up, no matter its value, with and without gravity sliding on the slope still occurs. Not sure how to fix this properly but we should stamp the bug label on this and get a proper fix in. This is a core function imo.

I would like to revert stop_on_slope from that function that seems not so good. You can always use the system with ray shape that reduz created https://godotengine.org/article/godot-31-will-get-many-improvements-kinematicbody

What do you think about it?

I would like to revert stop_on_slope from that function that seems not so good. You can always use the system with ray shape that reduz created https://godotengine.org/article/godot-31-will-get-many-improvements-kinematicbody

What do you think about it?

I love the raycast shape idea but it was already broken (more like unfinished though) even before stop_on_slope.
A single ray would work perrfectly and in any direction (there was no cast_to property but we could rotate it) but more than one ray would cause weird errors.
They behaved exactly the same with any slope_min_velocity value.

With stop_on_slope enabled the ray shapes behave very diffrently. Multiple rays don't cause errors anymore and they only work when pointing down but they cause some jittery collisiions with the floor.

Well stop_on_slope isn't fully working for me, but this issue is not about it.

(I would vote for reverting back to slope_min_velocity and fixing the raycast shapes)

I think this is more of a bug of stop_on_slope, @AndreaCatania can you give a check to this?
Raycast shapes now work, though.

Raycast shapes now work, though

More like "Raycast shapes kinda work", unless issue #25050 been addressed already.

The solution to this for now probably would be to not use snap if your character is not actually moving left or right (or use a threshold). I'm not quite sure this is a bug yet, but I plan to rewrite both KinematicBodies (2D and 3D) for 4.0 into a way where these things can be customized more. I will kick to then.

I've just encountered the exact same problem using the KinematicBody2D node. I was going mad.
I have the exact same behaviour as the one that @moiman100 described.
I've reviewed my code carefully and I'm (now) certain it is this very same Godot's bug.
If it can help: increasing the gravity force (increment on Y coordinate before using the method move_and_slide_with_snap) produce the same slippery issue with same velocity, so it should not depend on the "move and slide" sub-section of the method.
Specifying variables other than velocity, snap vector and floor normal vector doesn't affect the behaviour at all.

Just to add more infos, even if delayed:
on move_and_slide_with_snap, if stop_on_slope is false the velocity.x value is not zero after the method.
If it is true, velocity.x is zero and the character slides a bit slower.
immagine

Like @Scemenzo , I've also encountered the issue with KinematicBody2D. Kind of annoying, I thought the whole point of snap was to make working with slopes easier. Even with very gentle slopes and stop_on_slope enabled, the kinematic character will continue to move slowly down the hill. Going to try @reduz 's suggestion to use move_and_slide when not walking. Maybe try zeroing out the motion if it falls below a certain number.

This is kind of a fundamental problem with margins. Move an object down until it collides, then the margin will push it out along the normal. It's also (physics) framerate dependent. The more frames you have, the more frequently it'll get pushed out. Effectively the same issue as this:

https://github.com/godotengine/godot/issues/18624

As @jitspoe suggests, yes, the problem is that they're pushed out in the direction of the surface normal. What would be ideal, I think, would be to optionally specify the calculation of new margin vector based on angle of attack- In other words, separate the objects in the direction of velocity rather than direction of the normal, with that velocity-based separation's length calculated to the point where the objects are separated by a distance equal to the normal-based margin.

Was this page helpful?
0 / 5 - 0 ratings