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

Area2D does not detect moving StaticBody2D #81883

Open
KoBeWi opened this issue Sep 18, 2023 · 20 comments
Open

Area2D does not detect moving StaticBody2D #81883

KoBeWi opened this issue Sep 18, 2023 · 20 comments

Comments

@KoBeWi
Copy link
Member

KoBeWi commented Sep 18, 2023

Godot version

4.2 dev4

System information

Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1060 (NVIDIA; 30.0.15.1403) - Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz (8 Threads)

Issue description

If you have a stationary Area2D and a moving StaticBody2D, the body will not be detected. This used to work correctly.
The body is detected if the area itself is moving.

godot.windows.editor.dev.x86_64_srVEQCg5Iz.mp4

Steps to reproduce

  1. Add StaticBody2D
  2. Add Area2D
  3. Add some script to the body to make it move
  4. Connect area's body entered signal
  5. Nothing

Minimal reproduction project

Deadarea2D.tscn.txt

@Rindbee
Copy link
Contributor

Rindbee commented Sep 19, 2023

Not completely ineffective. It seems to be related to the starting position and speed.

 func _physics_process(delta: float) -> void:
-       position.y += delta
+       position.y += 4.0

In the case of the above changes, it can detect body enter; but if the starting point is changed, the situation may be different.

@BastiaanOlij
Copy link
Contributor

@KoBeWi not saying I agree with the change (I don't, it caused us a lot of headaches with XR), Godot introduced a new "static" type called AnimatableBody3D. That basically works like the old static body (and we've switched to it).

What is equally annoying and a far bigger problem for us, is that the same change applied to rigidbodys. If you freeze a rigidbody it also stops being detected. Which is a serious PITA for XR where we freeze rigidbodies when they are picked up by the user, but we still want them to detect them in areas as a lot of functionality uses that.

@BastiaanOlij
Copy link
Contributor

Owh and just to confuse matters more, if you move the Area3D node, it DOES detect static bodies and frozen rigidbodies! It's only when its the bodies that move and the area that is stationary, that we suddenly don't detect anything anymore.

@KoBeWi
Copy link
Member Author

KoBeWi commented Sep 19, 2023

AnimatableBody2D seems to do the trick, but I had to disable sync_to_physics, otherwise my custom movement wasn't working 🤔
If this is more or less intended behavior (i.e. staticbody not being detected), I think it should be documented at least.

@akien-mga
Copy link
Member

This was identified as a regression. What is the last release where it worked as expected?

@KoBeWi
Copy link
Member Author

KoBeWi commented Oct 30, 2023

It was fine in 3.5, not sure about 4.x.

@Occalepsus
Copy link
Contributor

Ok so if i understand the situation correctly, and according to the documentation, the moving static body does not interact with other bodies and areas. Should it emit a signal when entering an area?

@KoBeWi
Copy link
Member Author

KoBeWi commented Nov 5, 2023

If this is more or less intended behavior (i.e. staticbody not being detected), I think it should be documented at least.

Well...

When StaticBody2D is moved, it is teleported to its new position without affecting other physics bodies in its path.

That settles it I guess. It was documented all along.

Though Area2D is not a physics body, so maybe it deserves a bit more clarification.

@berarma
Copy link
Contributor

berarma commented Apr 22, 2024

When StaticBody2D is moved, it is teleported to its new position without affecting other physics bodies in its path.

That settles it I guess. It was documented all along.

Though Area2D is not a physics body, so maybe it deserves a bit more clarification.

I understand that piece of documentation as "it will not move other objects". In fact, it detects collisions with other bodies, it only fails with Area2D.

Same for RigidBody in freeze mode Static but in this case the documentation clearly states that it won't collide with other bodies (no mention to areas). Still, it will detect collisions with bodies but not areas, like StaticBody2D does.

The documentation is confusing and the behavior doesn't match any of the possible meanings we're considering.

Edit: And according to comments above overlapping areas will be detected if they move. We need a clear specification about when to expect collision detection and when not, but the way it works now makes it hard to explain and understand.

@casanccs
Copy link

casanccs commented Jun 19, 2024

@BastiaanOlij I have ran into this problem while developing a Table Tennis game. I set my paddle to be a pickable object, yet also have two StaticBody3D nodes inside the pickable object as a paddle has two different faces. When I pickup the object, the ball completely goes through the paddles (SOMETIMES! ONLY SOMETIMES!), while if I just assign position and rotation to follow the hand, it will NEVER go through the paddle.

@BastiaanOlij
Copy link
Contributor

@casanccs this sounds like a very different issue. Because you've got your static bodies (I'm assuming AnimatableBody3Ds) directly childed to the object held by the player, as the player moves their hand and the tracking data updates, you are actually teleporting the paddle from the previous position to the new position.

Time it just right, you're moving your paddle to hit the ping pong ball, and you teleport your paddle from before the ball, to behind the ball, with the ball seemingly going through the paddle.

What you need to do here is have your AnimatableBody3D follow the paddle using move_and_collide so that it properly collides with any object along the path of movement. And even then it's a hack because animatable bodies do not have velocity so you need to do your own calculations when the paddle hits the ball, both here as move_and_collide detects a collision with the ball, as well as when the ball in its physics process hits the paddle (which from its POV is stationary).

@miketvo
Copy link

miketvo commented Dec 11, 2024

I also ran into this problem while developing a Sokoban-style game. My push-able blocks were instances of a scene inheriting from StaticBody2D. In the same scene, I set up 4 surrounding Area2D to detect other box instances and the player.

The static boxes fail to detect a moving box coming next to them, which I expected would trigger body_entered for the corresponding Area2D detector. Instead, only the detectors on the moving box trigger the signal.

AnimatableBody2D seems to do the trick, but I had to disable sync_to_physics, otherwise my custom movement wasn't working 🤔 If this is more or less intended behavior (i.e. staticbody not being detected), I think it should be documented at least.
#81883 (comment)

Changing the type of the boxes to AnimatableBody2D does the trick, but I did not have to disable sync_to_physics. I guess it is because I do not have any actual movement interpolation for the boxes (I animate their sprites separately from their PhysicsBody, and set their position immediately upon the player pushing).

From the look of the discussion so far, and in the documentation for StaticBody2D, this indeed does seem like it is intended behavior since the introduction of AnimatableBody2D. I think the documentation should be updated to better reflect this, perhaps recommending the user to use AnimatableBody2D instead of StaticBody2D when it comes to being detected by Area2D while moving, and also mention specifically in the tutorial page for Area2D that StaticBody is not meant to be detected in that case).

Should the code documentation be updated as well? Since it still says in Area2D.body_entered and Area2D.body_exited that they will be emitted for PhysicsBody2D, which is inherited by StaticBody2D, so the natural conclusion is that StaticBody2D should act the same way as the other related classes.

Godot version: 4.3.stable

@berarma
Copy link
Contributor

berarma commented Dec 12, 2024

@miketvo, the documentation is talking about interaction between physics bodies, so if this was the intended behavior the documentation is very wrong and lacking. And then we have RigidBody that according to @BastiaanOlij exhibits the same issue.

This excerpt from the StaticBody2D doc:

A static 2D physics body. It can't be moved by external forces or contacts, but can be moved manually by other means such as code, [...]

When StaticBody2D is moved, it is teleported to its new position without affecting other physics bodies in its path. If this is not desired, use AnimatableBody2D instead.

So a StaticBody2D can be moved from code, that includes AnimationPlayer and RemoteTransform2D, and it won't affect other physics bodies in its path. Nothing said about StaticBody2D entering an Area2D, and on top of that, it's detected when the Area2D moves. So out of nowhere you can have an overlap event that might have actually happened long before is triggered. All while using StaticBody2D as the documentation states that it should be used. Much explaing to do in the docs.

An AnimatableBody2D might an equivalent or better choice in some cases but not all. What if we don't want the object to interact with other physics bodies when moving?

@miketvo
Copy link

miketvo commented Dec 12, 2024

@berarma thank you for pointing this out to me. The documentation is indeed not clear about how StaticBody would interact with Area, which is itself is not classified as a physics body as you mentioned.

TL;DR:

From my understanding, this issue is the result of the (maybe) confusing design of the built-in physics engine in Godot, and an equally confusing documentation. I'm not sure how accurate I am on this, so I would appreciate more input on my understanding of the engine.

From this understanding, to answer your question:

An AnimatableBody2D might an equivalent or better choice in some cases but not all. What if we don't want the object to interact with other physics bodies when moving?

  1. Not all physics bodies are equal. According to the current design of the physics engine: StaticBody and frozen RigidBody are not meant to be moved manually in code, and will not be detected by non-moving Area. Use AnimatableBody for this purpose instead, as the physics engine will properly support this.
  2. If we don't want the object to interact with other physics bodies when moving: One approach I can think of is to rely on the physics layer and mask system to toggle these interactions on/off as needed.

I know that this answer might not be the one that we were looking for, but for the time being, I think this is the best we could do to circumvent this issue.

If you're interested in my attempt at explaining why moving Area2D would still detect StaticBody and frozen RigidBody, please read below.

Detailed analysis:

I dug a little bit deeper into past issues and discussions relating to AnimatableBody and Area:

It seems that since the introduction of the new physics system into 4.x, there has always been some confusion surrounding the naming, behavior, and documentation of the physics bodies.

There's also #57539 (comment):

The current design of (the code of) Godot Physics is that unmoved areas do not collide with static bodies.

And to quote @BastiaanOlij:

Owh and just to confuse matters more, if you move the Area3D node, it DOES detect static bodies and frozen rigidbodies! It's only when its the bodies that move and the area that is stationary, that we suddenly don't detect anything anymore.

So to me, it seems that this is the intended design of Godot's physics system.

The point is that we were never meant to manually move StaticBody in the first place, and non-moving Area is not designed to detect moving StaticBody. If we think of it this way, then frozen RigidBody also should not be able to move, hence there is no need for it to be detected either.

Extending this logic, I think it is reasonable that moving Area would be able to detect physics bodies, including StaticBody and frozen RigidBody, based on the Godot's Physics engine philosophy: We use the moving Area as a collision detector for the player, and the StaticBody/RigidBody as walls/frozen obstacles.

It would then make sense that this is a documentation issue, as pointed out by @KoBeWi, but I also understand how this current design could become a problem, as @BastiaanOlij said:

@KoBeWi not saying I agree with the change (I don't, it caused us a lot of headaches with XR), Godot introduced a new "static" type called AnimatableBody3D. That basically works like the old static body (and we've switched to it).

What is equally annoying and a far bigger problem for us, is that the same change applied to rigidbodys. If you freeze a rigidbody it also stops being detected. Which is a serious PITA for XR where we freeze rigidbodies when they are picked up by the user, but we still want them to detect them in areas as a lot of functionality uses that.

P/S. Please excuse me if my explanation was a bit hard to follow as English is not my native tongue, but I tried my best to make sense of the current physics system in Godot.

@berarma
Copy link
Contributor

berarma commented Dec 13, 2024

More references to places where the documentation clearly diverges from the implementation. First the definition about what is a body and what's not and then the same information as before about static bodies being able to move from code.

Is there some place where this change in the implementation has been discussed? It would be clarifying.

@miketvo
Copy link

miketvo commented Dec 15, 2024

I think the documentation is really obfuscating on this regard.

Yes, static bodies are able to be moved from code, this behavior is introduced in #48908.

But I don't think it was the initial intention of the design, and it was very confusing, that's why we have AnimatableBody added in #52286 after the fact to address #2867.

The documentation was updated to include description for the physics body classes, but I am at a lost on where exactly it specifies how StaticBody and AnimatableBody should interact with Area. The best clarifying information I could find were these comments:

  • [4.0] StaticBody3D not detected into an Area #57539 (comment)

    The current design of (the code of) Godot Physics is that unmoved areas do not collide with static bodies. In the minimal reproduction project, the internal GodotAreaPair3D object (pairing the area and the body) gets created and hence added as a constraint to the body and to the area, but the Godot Physics step GodotStep3D::step just ignores it: it only considers the constraints of moved areas and active bodies (and static bodies are never active), so no collision is detected. The reason the higher velocity caused the collision to be detected is that the areas are considered "moved" on the very first frame (and the velocity was such that the collision happened on the first frame).

    In 3.x with Godot Physics the behavior is the same; no collision is detected after the first frame (though the AreaPairSW object gets created only after changing the tree_collision_mask to 3 in the BroadPhaseSW). In 3.x with Bullet Physics the collisions are detected (by design of the Bullet Physics server), which explains the discrepancy in the original report.

    To address this issue either the design of Godot Physics should be changed (to somehow consider more areas for collision, with the restriction that it should still be efficient), or this caveat should be added to the documentation of every relevant method and signal.

  • Moving staticBody collision not detectable #58710 (comment)

    So this new model of physics in 4.x is as clear as mud. 😀

    It is probably in a state of flux currently, hence the discrepancy between the docs and the current functionality and behaviour. I'm not quite sure what we can do to "fix" this in the meantime, other than wait for a new physics maintainer to sort this out.

    For instance the proposal is suggesting that StaticBody3D would have two modes, static and kinematic. And this seems to be what the current docs are based on. But in the engine, there is no static / kinematic switch (that I can see).

    I kind of get the idea, that for e.g. a moving platform you might want to make it static during some part of gameplay, and switch to kinematic at other parts. But I am ending up wondering whether this is worth the confusion versus just making it kinematic.

  • Moving staticBody collision not detectable #58710 (comment)

    Since that by design the staticBody cannot be moved, @pouleyKetchoupp did create a new body called AnimatableBody3D Add AnimatableBody inherited from StaticBody for moving platforms #52286 (and AnimatableBody2D) that can be animated and (as I tested in the MRP) detected by an Area (3D or 2D) when in motion.

    So, if you want a moving platform or doors, you need to use an AnimatableBody instead of a StaticBody.

However please take my interpretation of the documentation and the discussions around the physics engine's confusing behavior with a grain of salt. It seems like this has always been an issue ever since we moved away from Bullet physics starting from 4.0.

At the end, the fact of the matter is that StaticBody can be moved through code, but it is not going to be detected by unmoving Area, which to me looks like we are being discouraged from moving it unless we absolutely have to. Whether this is an intentional design or not, I am not completely sure, but we can all agree that the documentation is doing a poor job of explaining this to the user 😅.

@berarma
Copy link
Contributor

berarma commented Dec 15, 2024

AnimatableBody2D is a weird class. It's a kinematic body (interacts with other bodies) that fails to move correctly when the parent moves unless "Sync to physics" is on. The naming seems to imply that AnimatableBody2D can be moved while StaticBody2D can't, again this is confusing because of the naming. Body mode kinematic or static isn't related to the ability of the body to move, but to the ability to interact with other bodies instead. I think it adds more confusion to the original design.

If a StaticBody2D overlapping an area from the start, or when created at runtime, is detected, why can't teleporting it via code have the same outcome? I haven't checked it works in this way but I would guess it does.

The difference between "discouraging from moving it" and a bug is very hard to grasp for me. I lean more between a bug in the implementation or very bad documentation. Of course we're being discouraged from moving it but is it for the right reason? If StaticBody2D isn't meant to be moved in any way, that's what the documentation should say.

I think the initial design was pretty clear but it has been getting a bit muddy the more its implementation has evolved, the documentation hasn't kept up with the implementation, and we don't know which one is right. Of course, it's a lot easier to change the documentation than the implementation, but I think it would be in our best interest to go back to the design table and clear up the basic concepts and constraints.

I think godotengine/godot-proposals/issues/2867 hasn't been completely addressed and more could be done to make the physics easier to understand and use. The time that it's taking to fix fundamental issues in StaticBody2D/AnimatableBody2D suggests me there's something fundamentally wrong about them.

Take my words with a grain of salt too. I'm talking from my experience as a Godot user, I'm not deep into Godot physics development.

@miketvo
Copy link

miketvo commented Dec 17, 2024

@berarma I think your last comment perfectly sums up the situation we have right now with Godot 2D physics. AnimatableBody does feel like a bit of a "stop-gap" solution to address the peculiarity of the initial design having StaticBody being able to move via code. I agree that going back to the design table would be the best thing we could do to clear things up, as it does seem like this is a more fundamental issue rather than just a gap in documentation (although I still think the documentation needs work anyways).

Realistically, with the current state of the engine development, it looks like more focus is being placed in integrating Jolt as the default 3D physics engine (#99895), I don't have much expectation that this issue would be resolved quickly in the near future. Maybe in the mean time the documentation can be updated to help people avoid having to go down this rabbit hole.

Also as a Godot user, I don't go too deep into Godot physics development either. I'm not sure how much else I can contribute to our current discussion. In the next few weeks when I have more free time, maybe I can look into how other physics engines such as Box2D and Rapier approach this, perhaps then I may have some better ideas.

F.Y.I.:

If a StaticBody2D overlapping an area from the start, or when created at runtime, is detected, why can't teleporting it via code have the same outcome? I haven't checked it works in this way but I would guess it does.

I have tested this in my game: a StaticBody overlapping an Area from the start of the game does get detected, it is only when the StaticBody is teleported that it does not get detected by the Area anymore.

@KoBeWi
Copy link
Member Author

KoBeWi commented Dec 17, 2024

You can always bring up this issue on development chat if you want to discuss it further.

@jonathandw743
Copy link

jonathandw743 commented Dec 17, 2024

body_entered(body: Node2D)

Emitted when the received body enters this area. body can be a PhysicsBody2D or a TileMap....

A StaticBody2D is a PhysicsBody2D, so the docs are incorrect if this is intended (i don't know why this would be intended).

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

No branches or pull requests

9 participants