godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.75k stars 21.12k forks source link

move_and_collide() reports false negatives #67214

Open Gamepro5 opened 2 years ago

Gamepro5 commented 2 years ago

Godot version

4.0beta2

System information

Windows 10, Vulkan, Intel(R) Core(TM) i7-10875H CPU @ 2.30GHz

Issue description

I'm working on a replacement to move_and_slide() to fix several bugs with the function (namely this and others I haven't bothered making reports for yet). I'm making a fully custom movement system with move_and_collide(). I discovered that move_and_collide() has a specific situation where it gets several errors. When moving around on the flat ground (surface normal Vector3(0,1,0)) and applying a move_and_collide(Vector3(0,-0.1,0), true), It has a small chance to return a false negative (say there was no collision when there should have been one). This issue doesn't happen on slopes (aka when the normal isn't straight up).

The characterbody's collision shape is a default capsule shape, and the object it is colliding with is a rectangle (stretched cube).

This issue gets resolved by amplifying the snap vector's magnitude, but 0.1 should be more than enough. Setting it to 1 causes other issues.

Steps to reproduce

  1. Download and run the project
  2. Move around using WASD. Look at the output logs to observe errors. Each time something is reported, it is highly likely that a false negative was reported by move_and_collide().
  3. If an error is reported, it means the false negative occurred at line 93.

Minimal reproduction project

Custom_CharacterBody3D_Movement_System-main.zip

rburing commented 2 years ago

A workaround is to replace the line 93

var ground_check = move_and_collide(snap_vector, true)

by

var ground_check = move_and_collide(snap_vector, true, 0.001, true)

i.e. setting recovery_as_collision to true.

I still think there is an underlying bug with collision between thin boxes and spheres/capsules. Note the problem does not happen with a much thicker floor, or with a box/cylinder shape for the character.

Gamepro5 commented 2 years ago

I appreciate the workaround. The floor is already incredibly thick though, so I don't understand why this bug happens. Implementing your solution drastically reduces the amount of errors.

rburing commented 2 years ago

I suspect there may be a bug in the GJK-EPA implementation used by Godot. This should first be confirmed by finding a set of inputs (two shapes and their transforms) such that it fails, e.g. by running your project in a custom build of Godot with print_line statements added to print the input/output of GJK-EPA in here:

https://github.com/godotengine/godot/blob/3229194dfc6a03cceb8f544211ae71a0f1524987/servers/physics_3d/gjk_epa.cpp#L996

Then we can hunt for the bug and try to fix it, or try to find a better GJK-EPA implementation somewhere.