Skip to main content
Coding Quests

My Area2D signal never fires in Godot 4

Five things stop it, and the first two account for most of them: the layers and masks do not point at each other, or the detector is not monitoring.

Written against Godot 4.7.

Will these two see each other?

Set these the way your scene has them. The rule is directional: the area receiving the signal is the one whose MASK has to match the other area's LAYER. Putting both on layer 1 and masking nothing is the usual mistake, and it is how this starts out below.

Detector: collision_mask

The area with the connected signal. What it looks at.

Other area: collision_layer

The area being detected. What it is.

area_entered will never fire.

  • The detector's mask is empty. A mask of nothing detects nothing, and this is the most common version of this bug.

This covers areas detecting areas. For an Area2D detecting a body, the same rule applies to the body's collision_layer, and the signal you want is body_entered, not area_entered.

The five causes, in order

Work down this list rather than guessing. Every one of them is silent: there is no error, no warning in the output, and the scene looks right.

  1. 1. The mask and the layer do not meet

    The area receiving the signal needs its collision_mask to include the layer the other object is on. Both on layer 1 with empty masks is the usual version. Nothing errors, nothing warns.

    How to check: Open both nodes and compare the DETECTOR's mask against the OTHER's layer. Or use the checker below.

  2. 2. monitoring is off on the detector

    An Area2D with monitoring off is not watching for anything, whatever the layers say. It bites most often when something turns it off at runtime and never turns it back on. A hitbox that is only meant to be live during a swing, for example.

    How to check: print($Hurtbox.monitoring) in _ready, and again at the moment it should fire.

  3. 3. The wrong signal is connected

    area_entered fires for another Area2D. body_entered fires for a PhysicsBody2D. Connecting body_entered and then walking an Area2D through it is silent, and it reads correctly to anyone skimming the code.

    How to check: Is the thing you are trying to detect an Area2D or a CharacterBody2D? Match the signal to the answer.

  4. 4. There is no usable shape

    The Area2D needs a CollisionShape2D child with a shape resource assigned and not disabled. An empty one shows a warning triangle in the scene tree, which is easy to scroll past.

    How to check: Look at the scene tree for the warning triangle, and check `disabled` on the shape.

  5. 5. The connection never happened

    Connecting in _ready on a node whose script is not attached, or connecting on an instance that gets replaced, or editing the signal in the editor on a different node than the one in the running scene.

    How to check: print at the top of the handler. If nothing prints, put a print in _ready too and find out whether that even runs.

What a working one looks like

On the receiving area, with its mask set to the layer the hitboxes are on:

hurtbox.gd
GDScript
1
2
3
4
5
6
7
8
9
func _ready() -> void:
# The receiving area is the one that needs the mask.
area_entered.connect(_on_area_entered)
​
​
func _on_area_entered(area: Area2D) -> void:
if not area.is_in_group("hitbox"):
return
print("hit by ", area.get_parent().name)

The detected side needs no mask at all. A hitbox is not looking for anything, it is only being looked at. Give it a mask it does not need and you get two areas detecting each other, which is how damage ends up applying twice.

Next

Layers stop being confusing once you have built the pipeline once

The hurtbox detects, the hitbox deals, and the layers are what keeps them from hitting the wrong thing. You write it in the browser and it gets checked as you type.

Start free, 8 lessons