Area2D Detecting Collisions with CharacterBody2D but not StaticBody2D

Godot Version

4.2.2 Stable

Question

I am creating a game in which projectiles need to “break” (spawn particles and queue_free) on collision with an enemy or surface. My projectiles have an Area2D as a child that detects collisions between enemies and surfaces. For some reason, the body_entered signal and body_shape_entered signal are never emitted when colliding with a StaticBody2D, but they are emitted when colliding with a CharacterBody2D.

Using Godot’s built-in Change Type feature in the editor, I can turn any StaticBody2D in my scene into a CharacterBody2D while retaining all Collision Layers & Masks; the only difference is the type of the Node. The collisions with any node that was previously a StaticBody2D but had been switched to a CharacterBody2D do emit the signals! When switching back to a StaticBody2D, they do not.

Any ideas why this may be happening? My bad but temporary fix for the time being is simply to use CharacterBody2Ds in place of StaticBody2Ds.

Hi!
Sounds odd.
Did you double check the collision layers and masks?

Yes, the Collision Layers and Masks are all correct.

Ok. Try enabling the visible collision shapes and confirm that there is a collision between the Area2D nodes and static body, that they are actually overlapping.

$Area2D.monitoring = true

You can also check if the signals are still properly emitted after the change.

There is a visible collision between the two shapes when Visible Collision Shapes is turned on. The Area2D also has monitoring on. Remember, the Area2D collides fine if a StaticBody2D is replaced with a CharacterBody2D while retaining all layers and masks. It’s all very strange.

Yes, but is the signal even emitted on collision?

The projectiles’ Area2D nodes emit the body_entered signal when colliding with CharacterBody2Ds but not StaticBody2Ds, and I am not sure why. I could try creating a new project and duplicating the files over to see if the issue persists, but I would like to find the root of the problem.

Ok.
From the docs it appears the reason is how you set up the projectiles. Interpret player as projectile:

To detect the overlap, we’ll connect the appropriate signal on the Area2D. Which signal to use depends on the player’s node type. If the player is another area, use area_entered. However, let’s assume our player is a CharacterBody2D (and therefore a CollisionObject2D type), so we’ll connect the body_entered signal.

Hope this helps!

Thank you for your help, but I’m not really sure how this pertains to my problem. The projectile’s Area2D never detects collisions with StaticBody2Ds, while detecting collisions with CharacterBody2Ds works perfectly. The Area2D never needs to collide with other Area2Ds (I know when to use body_entered signals vs area_entered signals).

Without seeing your code, I can only come to a couple conclusions as to why this may be the case.

We can rule out layers and masks as you said changing the node type is the only variable that determines if it gets detected.

  • Did you change body in the function responding to the signal? For example:
func _on_area_2d_body_entered(body: CharacterBody2D) -> void:
	print(body)

If so this would explain why you only get a response from CharacterBody2D nodes. If this were the case, you should see errors in your debugger telling you it can not convert and object to an object. Personally I like to cast my body as a PhysicsBody2D type.

You have monitoring on otherwise you wouldn’t be detecting either body type.

  • Are you possibly filtering out the static body inside your function itself in some way? Without seeing the code it’s impossible for me to tell.