Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CharacterBody3D sliding along a wall with move_and_slide() has unexpected speed at certain angles #90410

Closed
p3tina opened this issue Apr 8, 2024 · 1 comment · Fixed by #90915

Comments

@p3tina
Copy link

p3tina commented Apr 8, 2024

Tested versions

Reproducible and tested in 4.2.1 stable, 4.3 dev 5, and 4.0 stable.

System information

Godot v4.2.1.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1070 (NVIDIA; 31.0.15.5176) - Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz (8 Threads)

Issue description

When a CharacterBody3D slides along a wall with move_and_slide() while rotating and its angle approaches parallelity with the wall, the body will reach an angle where it will first move at half speed and gradually speed up to double speed as the angle changes. It will return to the expected speed as soon as it stops colliding with the wall, or if the body turns back in the direction of the wall.

This issue occurs with both default physics and Jolt physics and regardless of the type of collision shape used on the CharacterBody3D, though the collision shapes do behave slightly differently.

Video of the issue being demonstrated with a cylinder collider on the body:

2024-04-09.10-23-43.mp4

And a video of the issue with a capsule collider, which is more jittery:

2024-04-09.10-30-17.capsule.mp4

Steps to reproduce

Run the test project and slide against the wall while rotating the camera very slightly.

Minimal reproduction project (MRP)

slide test.zip

@rburing
Copy link
Member

rburing commented Apr 10, 2024

Thanks for the MRP. This bug is probably somewhere in scene/3d/physics/character_body_3d.cpp.

I'm not very familiar with this higher-level code, but so far I notice at least one thing fishy: CharacterBody3D::move_and_slide resets collision_state before calling _move_and_slide_grounded:

collision_state.state = 0;

but CharacterBody3D::_move_and_slide_grounded uses it as the previous state:

CollisionState previous_state = collision_state;

so the following boolean can never be true (edit: on the first iteration, so maybe it's okay):

// Stop all motion when a second wall is hit (unless sliding down or jumping),
// in order to avoid jittering in corner cases.
bool stop_all_motion = previous_state.wall && !vel_dir_facing_up;

If we change it so that collision_state is not reset before calling _move_and_slide_grounded then that boolean does get set to true in the MRP, but there is no "second wall" as referred to in the comment (we were just touching the same wall in the previous tick), so the logic seems to be incorrect.

This is not the whole story though, it will need to be investigated further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants