godot: Area/Area2D doesn't detect static bodies if "Monitorable" is disabled (3D issue only when using GodotPhysics)

Godot version: 184b2fe

Issue description: This could also affect the 3D version of it, but I just tested in 2D.

If an Area2D’s Monitorable property is disabled, it will fail to detect static bodies.

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 14
  • Comments: 28 (23 by maintainers)

Commits related to this issue

Most upvoted comments

So it comes down to this, currently we need to make a decision, and from what I’m hearing here it sounds like users want everything to collide against everything.

The GD4 Area3D documentation says: 3D area that detects CollisionObject3D nodes overlapping, entering, or exiting.

So yes, that is what we expect (and how it works in GD3/Bullet). If any PhysicsBody with an enabled CollisionShape and matching layer/mask enters an Area, we should get body entered signals. If any PhysicsBodies collide with other PhysicsBodies with matching parameters, they should collide and send signals.

We also understand that we should be using StaticBodies for immovable objects, RigidBodies for physics movable objects, Kinematic/Character bodies for user movable object, and Areas for detection.

If there’s a better way to do it, fine. Us users don’t care about or understand pairable or not pairable or the BVH or the other magic you guys are doing under the hood. We just expect the code to work as advertised in the documentation and tutorials, and provides the functionality we need (present in GD3/Bullet). Currently GD4 doesn’t quite do that and the documentation is inconsistent.

So… what is the best way of detecting static bodies? Like, let say I want a character to jump BEFORE running off a ledged, then I want some kind of detector running in front of them that says when there isn’t any ground. I don’t want the detector to have any physics in it (hence shouldn’t be a body), I want it to only be a zone of detection.

This seems like something that “area2d” should do, or at least, have the ability to do. If not, then, what type of object should have that behavior.

I’m all for fixing some other thing that is a bug, but … if you do I’m not sure how to implement the thing I’m imagining.

The problem arises when moving Areas that are not monitoring collide with StaticBodies. Neither is checking for collisions, so nothing is detected.

No. The problem arises even when Areas that are monitoring collide with StaticBodies, or at least with tiles, in my case. Nothing is detected until your Areas have monitorable On, which doesn’t make sense, and that’s the bug, for what I’m able to understand.

In other words, to solve the bug, either:

  • nothing should be detected also when Area has monitorable On, but in this case you couldn’t detect tiles, so something would have to be done for making tiles detectable by Areas

OR

  • An Area should always detect StaticBodies if the Area has the monitoring parameter On (not the monitorable parameter).

http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html

Static body and area should not report contact

In my case I was trying to detect tiles from a TileMap. The documentation for Area2D says:

body_entered(body: Node) Emitted when a physics body enters. The body argument can either be a PhysicsBody2D or a TileMap instance (while TileMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).

But it doesn’t work unless you switch “monitorable” on, on the detector, which makes no sense.

Saw a few people had been bumping this and similar bugs. Just to review some options for fixing this (as I remember, it’s been a while so my memory may be wonky) for the benefit of new physics contributors such as @rburing :

Imo there are two good options which solve the bug (and don’t necessarily adversely affect performance in the situation where this mode is not needed). Both involve the need for an extra flag on Areas, whether or not the Area should collide test against Statics. Or alternatively the monitorable state could become more of an enum:

  • Normal (as before, Areas in the static tree)
  • Collide all (with statics)
  • Monitorable (collide with all and report collisions)

The two ways obvious ways of implementing this:

  1. Keep the same number of BVH trees (2), but alter the physics code so that when collide all is set, the Area is added to the dynamic tree instead of the static tree. This would be more expensive than normal mode, but not as expensive as monitable because there is no reporting.
  2. Add a third BVH tree (mostly similar to the code I already wrote in #58505 ) and place collide all Areas into this third tree instead of the static tree. This has the advantage that we could eliminate Area to Area collision checks.

Just to emphasize that we made the BVH totally configurable with the templated trees in #55640 , so it is possible to add / remove trees / configure collision masks without changing the actual BVH code at all (and thus requires no specialist knowledge), and this can be done by a physics contributor as in the approach in #58505 .

I was looking how to detect static bodies with a non-physical colliders and ENABLING MONITORABLE in Area2D is the only way.

It shouldn’t even be called a bug since area2D isn’t monitorable anyway(except by others Area2D, I know, but it can be handled with collision_mask bits). So, if Area2D isn’t supposed to be detecting static bodies in any way, please let this “bug” continue

I am not knowledgeable enough about physics engine internals to comment on the technical merits of any choice, but as a user, the idea that ‘monitorable’ and ‘collide all’ are two options in the same enum feels weird, since ‘monitorable’ is about being detectable whereas ‘collide all’ is about detecting other bodies.

@barbaros83 I can confirm this is considered a bug. When it’s fixed, it will very likely be on both 4.x and 3.x.

No, it’s definitely a bug. It’s just not an easy one to fix, because of the way the physics engine was designed.

The problem is with the way the physics engine is designed. To make things efficient, StaticBodies are not checked if they’re colliding with anything, because they don’t move. Instead it relies on the other CollisionObjects moving and detecting collisions with it. Similarly, to make things efficient, Areas that are not monitorable are not checked if they’re colliding with anything. The problem arises when moving Areas that are not monitorable collide with StaticBodies. Neither is checking for collisions, so nothing is detected.

Just looking at fixing this now. Here is a minimum reprod project (there was another earlier but it didn’t work well for me.

Just run it using either Godot physics or Bullet, it prints the “Area entered” message with Bullet but not with Godot physics.

Lawn_StaticAreaCollision.zip

lol, i was going crazy thinking i did something wrong, turns out its a long standing bug. is this going to be fixed in 3.x ? 1 of the comments suggests its not a bug, but it definitely is, because the dev should decide what the node should do, not asuming anything. in my game i have a building that i can place, wich is a staticbody, and the enemy characters are kinematicbody’s, with an area for detection, it makes sense the way its set up, and the way you would asume it works, if detection is not desired there are many ways to handle that, put it on a diffrent layer, or disable the body, filter the bodies that enter the area.

Experiencing this in 3.2.3 stable. It’s confusing enough that it took me quite a while to understand what was going on in my project. In my case I was trying to detect tiles from a TileMap.

@Ranoller Well, then the bug is that is detecting static bodies when Monitorable is enabled then?