-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Pausing causes various errors with Area2D
s
#61420
Comments
Still present in f38ea25 |
More oddities found with the new pause system while testing: |
Still present in 8a98110 |
I spent a while looking into this one, posting my findings here cause I am not sure what to do to fix: 1. Discrepancy in behaviour depending on who is on topWhoever is on top of the tree is the one "monitoring" for the other, then, when enabling/disabling the process mode code will follow different paths on 2. Signal's disconnectionThere isn't in fact a signal disconnection, but by the way the area2d function monitoring bodies coming in and out, when that is on top of the hierarchy (thus monitoring) and you set 3. Why is the callback not called when Area2D is the one monitoring but not when it's
|
The problem is that the Area2D is getting a new _body_inout event on unpause if the object is still in the Area2D. Because the body_map on the Area2D already has that object in it, it iterates the rc element. The iteration is done in line 195: Line 195 in c151d32
What I'm confused about now is what situation would require us to count the same body multiple times on the same Area2D. A quick-and-dirty solution is to just check if the body is already in the body_map, but that completely eliminates the use of the rc iteration. I made this change locally and tested it and it resolves the issue. We could also just explicitly set the rc to 1 one on line 185 and eliminate line 195: Line 185 in c151d32
IE if (body_in) {
if (!E) {
E = body_map.insert(objid, BodyState());
E->value.rid = p_body;
E->value.rc = 1;
E->value.in_tree = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree).bind(objid));
node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree).bind(objid));
if (E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
}
}
if (node) {
E->value.shapes.insert(ShapePair(p_body_shape, p_area_shape));
}
if (!node || E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
} I think there's two areas to further investigate:
|
It looks like this system is supposed to implement reference counting for a scenario where multiple object are referencing the same body_map object, but the implementation of Area2D as it currently exists creates a body_map for each instance of Area2D. I would need information from someone more knowledgeable about the physics engine as a whole, but it appears the only references to value.rc are within this specific function call. This is also an issue in Area3D |
Same error as in #70848 However, trigger conditions slightly differed. I the bug above, I could only trigger in timeout callback (re-enabling at any time), or during process/physics process by re-enable node immediately in same frame as disabling. It seems than manual toggle also triggers the bug in this demo, but I'm not sure of the exact conditions. |
I think I found the function calls related to the bug, it comes from I'll try to copy the call stack which causes it: Lines 3488 to 3490 in 7872594
-> godot/servers/physics_server_2d_wrap_mt.cpp Lines 73 to 75 in 7872594
-> godot/servers/physics_2d/godot_physics_server_2d.cpp Lines 1282 to 1284 in 7872594
-> godot/servers/physics_2d/godot_step_2d.cpp Lines 255 to 257 in 7872594
-> godot/servers/physics_2d/godot_step_2d.cpp Lines 84 to 86 in 7872594
-> godot/servers/physics_2d/godot_area_pair_2d.cpp Lines 72 to 74 in 7872594
-> godot/servers/physics_2d/godot_area_2d.h Lines 162 to 164 in 7872594
-> godot/servers/physics_2d/godot_area_2d.cpp Lines 199 to 201 in 7872594
-> godot/servers/physics_2d/godot_space_2d.cpp Lines 1099 to 1101 in 7872594
I am not sure what the solution would be, so I am not opening a PR yet |
It happens when disabled because the monitor_query_list is emptied of the area when both paused and disabled (There is a call to |
1. Wrong behaviors caused by pauseIt takes two to make a collision. If either is disabled, collision will no longer exist. It should be noted that unpair will cause the area to eventually be added to godot/servers/physics_2d/godot_area_2d.cpp Lines 66 to 68 in ba54c34
If it is disabled in the order of A-B (Area-Body), the area will eventually be added to the godot/servers/physics_2d/godot_space_2d.cpp Lines 1126 to 1130 in ba54c34
That is, in the above code, 2. Error message during resumed
For the error message during resumed. The body is paired with the area in place and becomes active. This causes the same body to be added to the godot/servers/physics_2d/godot_area_pair_2d.cpp Lines 99 to 101 in 4df80b0
godot/servers/physics_2d/godot_body_2d.cpp Lines 410 to 412 in 4df80b0
|
Tested the new PR. While it doesn't fix the problem enough to close out this ticket, it's still a big step forward. However, I am curious if it is intentional that pausing/unpausing a scene causes enter/exit signals to retrigger in Area*D's. That is the current behavior, so unrelated to the referenced PR, but it's definitely problematic. My wonder is if it's more or less problematic if it does than if it doesn't. |
I would expect signals to not be retriggered after unpausing. I imagine pausing as some kind of hole in Node's lifetime. It should not affect its behaviour. After unpausing it should stay at the exact same state it was when it was paused. EDIT: Current behaviour seems to be especially problemiatic in case you want to know if Node exited Area2D but this Area does not care if the object was paused or not meanwhile. It wants to know if it actually left. |
Hey, is there any workaround for this issue right now on 4.2 stable? Seems kinda of a big deal that the engine just breaks itself if you happen to pause while inside an Area2D collision shape. Sorry if I seem a little salty. I really love Godot and I know its not anyone's fault, but it's just that I've been banging my head against a wall for an entire day trying to make this work, just to find out its a bug. |
Godot version
4.0.dev (a534346)
System information
Windows 10
Issue description
If a body is within an
Area2D
'sCollisionShape2D
when the scene is paused and resumed two things happen:If the body is higher in hierarchy (behind the
Area2D
), all signals are disconnected from theArea2D
.2022-05-25.15-37-33.mp4
If the body is lower in the hierarchy (in front of the
Area2D
), errors are written to the console.2022-05-25.15-29-50.mp4
Steps to reproduce
CharacterBody2D
with collision.Area2D
with collision.BodyEntered
signal forArea2D
.Area2D
.Minimal reproduction project
CollisionBugGD.zip
(converted to GDScript project)
The text was updated successfully, but these errors were encountered: