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

Disabling process of PhysicsBody2D and containing Area2D on same frame will make area register body as entered forever #76219

Closed
hsandt opened this issue Apr 18, 2023 · 10 comments · Fixed by #81809

Comments

@hsandt
Copy link
Contributor

hsandt commented Apr 18, 2023

Godot version

v4.0.2.stable.official [7a0977c]

System information

Linux Ubuntu 22.04 with Unity desktop

Issue description

I have a Restart functionality in my game that respawns all my characters to their initial positions.

Some of my code uses Area2D.get_overlapping_bodies and the doc says it doesn't take rigibody moves in the same frame. Indeed, I saw an enemy sometimes thinking my character was still there for 1 frame and try to attack it.

So, I disabled the process mode of my warped characters (process_mode = PROCESS_MODE_DISABLED) only to reenable it one or two frames later. Since one character has a detector Area2D, and the other has a detected PhysicsBody2D (CharacterBody2D, but other sub-types also have the issue), I'm disabling both at the same time.

I noticed that when the PhysicsBody2D is inside the Area2D, the Area2D keeps registering the PhysicsBody2D forever, even after I re-enable them or move them. This can be seen when accessing both get_overlapping_bodies or a manual array updated in _on_body_entered and _on_body_exited via signals.

Note: if you work with a CharacterBody2D and move it outside the Area while it's disabled, then re-enable it, it will be registered for 1 frame, as if its collision shape was still at the old position, then immediately unregistered. This has already been reported in #69407 and StaticBody2D doesn't have the issue, so it must be unrelated to our particular issue.

Steps to reproduce

  1. Play the Test2D scene
  2. Overlapping bodies count should be 1 (the big character body is not overlapping the area by default, only the static body is)
  3. Press T to call toggle_body_and_area() which will disable the static body and the circle area. They will appear in red
  4. Observe the count is still 1
  5. Press T again: the count is still 1
  6. Play with the A (toggle area), B (toggle body), N (move area), M (move body), but nothing will unregister the body from the area
  7. You can restart the game to try different combos, but the easiest ways to trigger the bug are still T and S (which simulates the actual game restart sequence I had in my game; not the minimal actions though). You can also press B and A exactly on the same frame, but it's harder to do.
  8. You can finally move the StaticBody2D away and place the CharacterBody2D to overlap the Area2D instead. Remember to re-assign Test2D > Inspector > Body to CharacterBody2D. In this case, the result in the same. The only difference is that you can trigger bug #69407 mentioned above, by pressing B -> M -> B

Minimal reproduction project

v4.0.2 - PhysicsBody2D stays registered in Area2D when disabled inside.zip

EDIT: oops, forgot to remove the 3D scene
It'll be worth testing 3D too, but in this case the 3D scene has not been setup, so you can ignore it.

@markdibarry
Copy link
Contributor

Possible duplicate of #61420

@hsandt
Copy link
Contributor Author

hsandt commented Apr 18, 2023

Possible duplicate of #61420

I saw it, but it's closer to #70848
I'll add some comments there though to add my findings and link to that issue.

@markdibarry
Copy link
Contributor

markdibarry commented Apr 18, 2023

It seems like the same root cause, but I could be wrong. I saw someone opened a PR to fix it the other day, but I haven't looked into it too much.
Edit: Never mind. They closed the PR.

@hsandt hsandt changed the title Disabling process of PhysicsBody2D and containing Area2D will make area register body as entered forever Disabling process of PhysicsBody2D and containing Area2D on same frame will make area register body as entered forever Apr 18, 2023
@hsandt
Copy link
Contributor Author

hsandt commented Apr 27, 2023

... and I found a bug variant today: disabling and re-enabling Area2D containing PhysicsBody2D on same frame will register PhysicsBody2D forever.

To repro, reuse the MWE above and modify toggle_body_and_area to do:

		toggle_process(area)
		toggle_process(area)

Play, press T, then M to move the body away and notice the count is still at 1 instead of 0.

You can also check that waiting 1 frame before the re-enabling:

		toggle_process(area)
		await get_tree().physics_frame
		toggle_process(area)

does not trigger the issue.

@hsandt
Copy link
Contributor Author

hsandt commented Apr 27, 2023

OK, I see how #61420 can be helpful now

It seems like the same root cause, but I could be wrong. I saw someone opened a PR to fix it the other day, but I haven't looked into it too much. Edit: Never mind. They closed the PR.

Indeed, but I see that the research (esp. hcoura's observations) may in fact be useful for this issue too.

@hsandt
Copy link
Contributor Author

hsandt commented Apr 27, 2023

For now, I used the following workaround in a real project, and it works:

  • I make sure to disable my various nodes one by one, waiting one frame between each disabling (an attentive eye will notice the nodes freezing or, in my case, disappearing; but you can fade out screen before so it's not visible)
  • I make sure to wait at least one frame before re-enabling the nodes (in my case, the await get_tree().physics_frame I put after disabling also serves as delay before re-enabling)

tbxMb added a commit to tbxMb/godot that referenced this issue May 21, 2023
… and containing Area2D on same frame will make area register body as entered forever
tbxMb added a commit to tbxMb/godot that referenced this issue May 21, 2023
Partial Fix:  GH: godotengine#76219 Disabling process of PhysicsBody2D and conta…
@felbecker
Copy link

I don't think changing process_modes one by one is a good workaround. Normally, we are supposed to use the inherit mode to propagate down the tree, so such a workaround would require large rewrites of code. Unfortunately, I don't see a better way after scanning this and related issues.

As a very nasty side-effect this bug seems to break games that use VisibleOnScreenEnabler2D (and apparently this bug occurs in 3D as well) as it makes use of the process mode.

@DrRevert
Copy link
Contributor

Issue also occurs for the 3D counterparts, was about to report as a new issue before finding this one. Here's a project reproducing the issue in 3D. Tested in 4.1.1
delete_body_in_area.zip

@fredlim
Copy link

fredlim commented Sep 15, 2023

Issue also occurs for the 3D counterparts, was about to report as a new issue before finding this one. Here's a project reproducing the issue in 3D. Tested in 4.1.1 delete_body_in_area.zip

Tested in 4.1.1 with Jolt physics and found no issue.
delete_body_in_area_jolt_x64.zip

@felbecker
Copy link

I tested the MRP under Godot 4.1.2 with this fix: #81809. The issue was gone.
Godot 4.1.2 without the fix still has the issue.

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.

7 participants