godotengine / godot

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

KinematicBody2D can push other KinematicBody2D #34345

Open securas opened 4 years ago

securas commented 4 years ago

Godot version: 3.2, beta 3

OS/device including version: Windows 10

Issue description: A kinematicbody2d can unintentionally move another kinematicbody2d when the latter should not be able to move in a given direction.

Steps to reproduce: Try the example project. Block on the left is stock KinematicBody2D and cannot be moved by the player. Block on the right is the same but with a script to implement gravity. That block can be pushed by player although there is no code to implement its horizontal motion.

Minimal reproduction project: test_unwanted_pushblock.zip

KoBeWi commented 4 years ago

That's how kinematic bodies work. They move in given direction, but also react to detected collisions.

securas commented 4 years ago

That's not true. What you are describing are rigid bodies.

KoBeWi commented 4 years ago

No, I mean that when you move a kinematic body towards another kinematic body, it might end up "inside" it and when you use move_and_slide in that collided body it will try to move out. Although maybe this shouldn't happen...

securas commented 4 years ago

In my view, if a body is "pushed", the body doing the pushing should move. Not the body being pushing. Otherwise this is an unpredictable behavior.

securas commented 4 years ago

In any case, both boxes react in a totally different way when being pushed. Hence, this should be fixed at the very least for the sake of consistency.

eon-s commented 4 years ago

Separation on the move resolution will make a body to be pushed if is too close to another, you can reduce the safe margin of the body that must not be pushed and increase the other to make sure it will not end on an overlapping state that "pushes" bodies.

In this case, since you are working at very small scales (where precision affects a lot and physics tend to fail) the method mentioned before may not be easy to apply and the best solution will be to not use move on things you do not want to move, that will also help the physics server because working with many overlapping KB can be expensive.

securas commented 4 years ago

Separation on the move resolution will make a body to be pushed if is too close to another, you can reduce the safe margin of the body that must not be pushed and increase the other to make sure it will not end on an overlapping state that "pushes" bodies.

Unfortunately, changing the safe margin does not solve the problem. It just delays it. It can still be exploited by players

In this case, since you are working at very small scales (where precision affects a lot and physics tend to fail) the method mentioned before may not be easy to apply and the best solution will be to not use move on things you do not want to move, that will also help the physics server because working with many overlapping KB can be expensive.

This problem also occurs at large scales. I've attached an equivalent project with large elements.

To me, it seems to be a synchronization problem between physics computations between both bodies. Note that none of the boxes should ever move. But only the box that is actually computing collisions moves. This would indicate that something is wrong with those computations.

securas commented 4 years ago

test_large_unwanted_pushblock.zip

eon-s commented 4 years ago

On my tests, on the first example a margin of 0.001 makes it unpushable by the player with margin 0.08; on the second example can be used a safe margin of 0.01 and is enough, if the margin of the player can be increased, it will give better results.

securas commented 4 years ago

Thanks for trying. Setting the margin to lower values still moves boxes. Just slower, making the behavior unpredictable with variable frame rates.

On Mon, Dec 16, 2019, 19:02 eon-s notifications@github.com wrote:

On my tests, on the first example a margin of 0.001 makes it unpushable by the player with margin 0.08; on the second example can be used a safe margin of 0.01 and is enough, if the margin of the player can be increased, it will give better results.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/godotengine/godot/issues/34345?email_source=notifications&email_token=AAV7RW4H55AGR2XEPMB37I3QY5G4PA5CNFSM4J2YPC4KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEG6FJYA#issuecomment-565990624, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAV7RWZT5JUMP5MHRWCT3PLQY5G4PANCNFSM4J2YPC4A .

eon-s commented 4 years ago

This issue may be related to #8757. The physics server may need to know what was the previous position before attemping separations like, if it is the same position (or close enough), leave it alone regardless of a move applied to it.

securas commented 4 years ago

Well... This is not a separation. But indeed might be related. Kinematic bodies should not have physics other than collisions. Motion coming out of the collisions should be coded and not handled unpredictability by the engine. I found yet another bug in this... Jumping on to a box can make it fall through a platform if the platform is one way. Thought this was only with rigid bodies but it seems that indeed the engine is forcing motion after collisions, leading to problems.

AttackButton commented 4 years ago

I found this problem today with a KinematicBody2D with velocity.y equals 0.0 in the air and no gravity. Jumping over and over it changes it's position.y slowly.

ghost commented 4 years ago

Seems to happen specifically when the affected KB is doing move_and_slide() that will make it collide/intersect with something else. In the context of your project, I'm guessing it is resolving itself out of the floor geometry and then takes into account the other collision too.

Another wrinkle to it, is that it seems that only specific velocities on the player will cause it. If you speed it up some, it doesn't seem to be occurring.