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

Fix body leaving area gravity influence #82961

Merged
merged 1 commit into from Dec 22, 2023

Conversation

Occalepsus
Copy link
Contributor

@Occalepsus Occalepsus commented Oct 7, 2023

This pull request fixes and closes issue Area3D gravity problem in Godot 4 #77682

We solve this issue with @Wiltof by adding a check in the destructor of GodotAreaPair3D ; if the area has a gravity override then we remove the area from the body so it is not influenced by it anymore.

This solves the cases where we have a Rigidbody3D inside an Area3D with a gravity override mode, when the RigidBody3D is teleported outside the Area using its Tranform, or when the Area3D is disabled or deleted. The RigidBody3D is no longer subject to the Area3D gravity.

@Occalepsus Occalepsus force-pushed the fix_body_area_gravity branch 2 times, most recently from 6ca7a3d to 3d13e30 Compare October 11, 2023 14:50
@AThousandShips AThousandShips changed the title Fix #77682 Area 3D gravity problem Fix Area gravity problem Oct 11, 2023
@Occalepsus
Copy link
Contributor Author

I made modifications in the code to solve all space override cases. To do that, I created a new field in GodotAreaPairXD (with XD is 2D and 3D, i've modified both at the same time) which is a bool called body_sub, that corresponds to the state where the area is in GodotBodyXD::area. body_sub is changed each time the area is added or removed in the methods of GodotAreaPairXD.
At last, in GodotAreaPairXD::~GodotAreaPairXD(), if the area is in GodotBodyXD::area, that we know thanks to body_sub, then we remove it.

I've seen that this PR might be in conflict with #81434 and #82470, but this PR covers more case and is more efficient since the field has_space_override is not computed each frame, but only when needed.

@AThousandShips AThousandShips modified the milestones: 4.2, 4.3 Nov 9, 2023
@AThousandShips AThousandShips added cherrypick:4.1 Considered for cherry-picking into a future 4.1.x release cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release labels Nov 9, 2023
@FeralBytes
Copy link
Contributor

This is definitely needed I hope it gets merged soon, because the current behavior in Godot 4 is incorrect and even unpredictable at best.

@radishes
Copy link
Contributor

Thank you for this fix. Would love to see this approved to go into production as soon as possible 🙏

@NolanDC
Copy link
Contributor

NolanDC commented Nov 27, 2023

Even though it's less efficient, it may actually actually makes sense to calculate has_space_override every frame so that that anyone working in this class can assume that all the variables are in their correct state after setup is called.

Also, totally a nitpick, but I wonder if the variable name could be a bit more descriptive. Maybe something along the lines of body_has_attached_area? I don't think I'd quite know what body_sub was referring to unless I dug into the code.

@Occalepsus
Copy link
Contributor Author

Also, totally a nitpick, but I wonder if the variable name could be a bit more descriptive. Maybe something along the lines of body_has_attached_area? I don't think I'd quite know what body_sub was referring to unless I dug into the code.

Good point! Indeed I put that name to test something at first, and then totally forgot it. If you think it is really needed I can update the PR to refactor this variable name.

@NolanDC
Copy link
Contributor

NolanDC commented Nov 29, 2023

Sure! I think anything that improves clarity is always worth doing, especially if it's easy to change.

@radishes
Copy link
Contributor

Looks like the requested updates are in. Are any other changes needed for the review?

@rthugh02
Copy link

Hoping to see this pushed soon, I believe the project I'm working on is affected by this issue. My setup:

  • On mouse click, an Area2D and a RigidBody2D are spawned at mouse position.
  • Area2D editor values are gravity_space_override = SPACE_OVERRIDE_REPLACE, gravity_point = true, gravity_point_center = Vector2(), gravity = 1370
  • While mouse click remains held, Area2D.position is set to mouse position.
  • On mouse click release, Area2D.queue_free() is called

My intention was for the RigidBody2D to no longer be affected by the gravity of the Area2D, but this is not the case. It appears that the last known gravity_point_center remains "in tact" so to speak. Video of this behavior:

gravity.still.active.mp4

@YuriSizov YuriSizov changed the title Fix Area gravity problem Fix body leaving area gravity influence Dec 15, 2023
Copy link
Contributor

@YuriSizov YuriSizov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks sensible, good catch! Should this also be done to GodotAreaSoftBodyPair3D?

Also, could you amend the commit message so it doesn't include the issue reference? You can add it to the body, just not the title.

@rburing
Copy link
Member

rburing commented Dec 15, 2023

Thanks for this PR, I think it has the right spirit but not exactly the right solution. I think the role of the newly added variable body_has_attached_area should already be played by the existing has_space_override. The bug is that it gets set to false too often in GodotAreaPair2D::setup, GodotAreaPair3D::setup, and GodotAreaSoftBodyPair3D::setup.

Indeed, in the current master branch has_space_override can only get set to true on the tick where colliding changes from false to true or vice versa, and on the next tick (assuming colliding doesn't change again) it will get reset to false for no reason, which will eventually cause the bug of the destructor not doing the necessary cleanup.

I think the fix should be just this (in each of the three setup functions mentioned above):

-       has_space_override = false;
        if (result != colliding) {
+               has_space_override = false;

That is, it should just be the initial value in the branch where we're checking if the area overrides anything.

This also fixes the three linked issues in my testing.

@NolanDC
Copy link
Contributor

NolanDC commented Dec 15, 2023

@rburing Does that still leave some possibility that a programmatic change of the Area2D's override mode could result in the connection not being removed?

I might be missing something, but I think in theory:

  • mode is set to COMBINE
  • objects collide, area2 connection is added
  • mode is programatically set to DISABLED
  • objects stop colliding, but has_space_override is now false, so the body is not removed

This is why I closed my original solution here: https://github.com/godotengine/godot/pull/81434/files, since it would have a similar issue.

@rburing
Copy link
Member

rburing commented Dec 15, 2023

@NolanDC Good point, this PR covers that case while my suggested alternative doesn't.

So as #82961 (review) suggests the commit message should be updated to remove the issue number from the first line and the same approach should be applied to GodotAreaSoftBodyPair3D, and then this is good to go.

@Occalepsus
Copy link
Contributor Author

Oh thanks for all of your messages, I'll look to make the changes in GodotAreaSoftBodyPair3D and GodotAreaSoftBodyPair2D (if that exists).

@rburing right now I don't remember why, but I think there was something that made me create this new field, i'll see.
I'll make these changes and also change the commit name then.

@Occalepsus
Copy link
Contributor Author

@rburing i just tried your fix and I agree with NolanNC, the fix does not cover the case when the body is in the area while it gets deleted or disabled. I still think both has_space_override and body_has_attached_area are two separated variables with their own use.
In my commit amend i've changed the commit message and added the fix in GodotAreaSoftBodyPair3D.
Don't hesitate to tell me if there is anything!

Copy link
Member

@rburing rburing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM.

@YuriSizov YuriSizov merged commit bb1cdc1 into godotengine:master Dec 22, 2023
15 checks passed
@YuriSizov
Copy link
Contributor

Thanks! And congrats on your first merged Godot contribution 🎉

@radishes
Copy link
Contributor

Thanks everyone, this is an important fix for me and many others.

@Occalepsus Occalepsus deleted the fix_body_area_gravity branch December 23, 2023 10:20
@graehu
Copy link

graehu commented Jan 18, 2024

Hi, I've been writing a quick fix for something similar and just want to confirm if this will also fix the issue. I don't teleport my object, but I do set it to be kinematic / frozen and move it. Then when I unfreeze it in a new location, it's still got areas associated with it.

My fix was to write a script function that clears areas, and do that when I set the body kinematic.

https://github.com/graehu/godot/tree/body_areas_fix

If this fixes that I can remove my branch. 🙂

Edit: Tested myself, this fixes the issue! thanks!

@YuriSizov YuriSizov removed the cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release label Jan 24, 2024
@YuriSizov
Copy link
Contributor

Cherry-picked for 4.2.2.

@YuriSizov YuriSizov removed the cherrypick:4.1 Considered for cherry-picking into a future 4.1.x release label Jan 24, 2024
@YuriSizov
Copy link
Contributor

Cherry-picked for 4.1.4.

@ericvennemeyer
Copy link

Hi everyone, I'm a fairly new Godot user and just upgraded to 4.2.1. I am currently experiencing this exact problem and it's game breaking for me. It looks like this fix may not have made it into an official release yet. If that's the case, how do I go about testing it out for myself the way others on this thread seem to have?

Thanks for helping out a noob :)

@FeralBytes
Copy link
Contributor

@ericvennemeyer the fix is not in 4.2.1. It should be in 4.2.2, 4.1.4, and 4.3, when they are released. You should try one of the latest development releases to get the fix.

@ericvennemeyer
Copy link

ericvennemeyer commented Feb 22, 2024

@FeralBytes will do. Thanks for the quick response!

Edit: 4.1.4 dev release fixed it for me. What a relief! Thanks again

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