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

Very "squishy" collisions when setting linear_velocity of RigidBody2D #332

Open
trickster721 opened this issue Jan 7, 2025 · 14 comments
Open
Labels
bug Something isn't working

Comments

@trickster721
Copy link

Describe the bug

I'm using a RigidBody2D as a mouse cursor by setting the linear_velocity. The RigidBody2D's shape is a 8px diameter circle, the walls are 16px squares. When pushing against other bodies, the shapes are being allowed to tunnel/overlap significantly. GodotPhysics (and previously Box2D) prevents the shapes from overlapping as expected, with no project changes.

I experimented with project settings and saw no improvment. Setting linear_velocity directly in _physics_process (not intended?) or setting the state in _integrate_forces both give the same result. I'm using TileMapLayers, but plain StaticBody2Ds give the same result.

test.mp4

It's not shown clearly in the video, but there's also a very significant ghost collision effect when moving along the edges of the tiles.

To Reproduce

Move a RigidBody2D by setting the linear_velocity each physics frame.

Expected behavior

Setting the linear_velocity should result in correct collision behavior and prevent shapes from overlapping.

Environment:

  • OS: Windows 10
  • Version: latest
  • Godot Version: v4.3.stable.official [77dcf97d8]
  • Type: tested with both, same result

Example project(zip)

rapier-issue-minimal-example.zip

@trickster721 trickster721 added the bug Something isn't working label Jan 7, 2025
@Ughuuu
Copy link
Contributor

Ughuuu commented Jan 7, 2025

Do you have the ghost collision setting turned on?

@trickster721
Copy link
Author

Do you have the ghost collision setting turned on?

I don't think so. The ghost_collision_distance project setting is left at zero. Non-zero values make the issue worse.

@Ughuuu
Copy link
Contributor

Ughuuu commented Jan 7, 2025

And if you just do apply_impulse directly? Does this happen then?

@Ughuuu
Copy link
Contributor

Ughuuu commented Jan 7, 2025

I'm not 100% sure of how rapier is written, and if this happens because of misuse (should you directly set the velocity?)
Also, one thing you can try is playing with the project settings, because there is the acceptable error, and other things that might make things more robust, at the expense of other things.

@Ughuuu
Copy link
Contributor

Ughuuu commented Jan 7, 2025

The settings are at ProjectSettings -> Physics -> Rapier or smth like that. See if you change some of those if this improves.
Also try with ccd see if anything changes.

@trickster721
Copy link
Author

And if you just do apply_impulse directly? Does this happen then?

Yes, it's the same.

I'm not 100% sure of how rapier is written, and if this happens because of misuse (should you directly set the velocity?)

I think it's common to do this, it seems like the logical way to do the equivalent of move_and_slide with a RigidBody2D. The Godot documentation specifically mentions that it should be done in _integrate_forces instead of _physics_process. GodotPhysics and Unity's implemention of Box2D seem to support it just fine, and so did the previous Godot Box2D plugin.

Also, one thing you can try is playing with the project settings, because there is the acceptable error, and other things that might make things more robust, at the expense of other things.

I've tried changing all the project settings to a few different random values with no luck, if you have any specific suggestions for sane values I'll try those.

Also try with ccd see if anything changes.

I've tried setting both ray and shape continuous modes, with substeps project setting values like 5, 10 and 100. No change from any of that.

@trickster721
Copy link
Author

I tested this more, and it seems like it might just be the result of collisions being very "squishy" in general. I set Continuous CD to Cast Ray and used a simple constant force to repeatedly slam RigidBody2D circles of different sizes into a square tile, and measured the max amount they were left overlapping at the end of a frame. Rapier left the shapes overlapping by about 25% of the diameter, and then slowly separated them over several frames. With impulses or setting the velocity directly, it's even worse, 50% of the circle is stuck in the wall. Changing Normalized Prediction Distance to a much higher value improves forces, but does nothing for impulses.

GodotPhysics seems to work similarly, but only allows shapes to overlap about half as much, and separates them much faster, so the "bounce" is less noticeable. Box2D always resolves the collision in one frame and leaves the shapes separated by 0.44 pixels.

I feel like I must be missing some obvious way to reliably prevent tunneling.

@trickster721
Copy link
Author

trickster721 commented Jan 10, 2025

Doing more testing and stepping though frame-by-frame, it really seems like collisions just aren't being checked in advance at all, they're only being detected after shapes are already overlapping. The RigidBody2D just teleports into the StaticBody2D like it's not there, then reacts next frame. I think something really fundamental is broken. Surely Rapier is supposed to have some kind of "real" collision detection, at least with CCD turned on?

rapier2d

It takes 10 frames for the shapes to fully separate, using apply_force() with CCD set to Cast Ray and the default project settings. That's the kind of behavior I would expect from teleportation, not collision checking.

@Griiimon
Copy link

The settings are at ProjectSettings -> Physics -> Rapier or smth like that. See if you change some of those if this improves. Also try with ccd see if anything changes.

These settings helped to improve the behavior significantly. I wonder if the default settings should be closer to those, but I have no idea what the trade-off is. This was just trial and error, I can only guess what these settings mean.

rapier settings

@Ughuuu
Copy link
Contributor

Ughuuu commented Jan 11, 2025

@trickster721 I'm not sure about your question. It could be also related to the size of objects? It's possible since object is too small it is showing this behaviour? I am using some defaults in the project settings, but its possible those might need updated? Not sure, sorry. If you want you can open an issue on rapier side and ask the question and link this issue there, see if they know more.
@Griiimon Thanks for the suggestion, in your case you do not see this behaviour as much after setting those?

@Griiimon
Copy link

Yes, now the collisions seem like hard collisions, more like with the default physics engine.
The frequency setting has the most effect.
I can't really tell how much of an impact the prediction setting has.

@Ughuuu
Copy link
Contributor

Ughuuu commented Jan 11, 2025

It's possible that a higher frequency affects stability of objects? Not sure tho what the downside might be. Probably if objects move faster, you want a higher frequency, or if you care about the objects separating fast enough.
Edit: I wonder, how big is the initial circle you had in the example?

@Griiimon
Copy link

I went with the original MRP, made no changes. So 8px diameter.

I guess to really find out how this setting affects other scenarios one would need a diverse sandbox that contains lot of different bodies, some driven by different scripts and diverse level geometry.

...Or understand the source-code where this setting is applied, which I know I don't without having looked at it.

@Ughuuu
Copy link
Contributor

Ughuuu commented Jan 13, 2025

8px diameter, that means 8px / 100px (100 px per meter), that means 0.08 meters diameter. You could either make things bigger, or change the pixels per meter constant. That affects some things, including global project settings. Having such a small object might not perform perfect, I wonder if the object has 100 pixels (1 meter) if it performs better or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants