Area2D _area_entered signal stops firing despite overlaps detected

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By dilettante

I am trying to spawn multiple Area2D nodes with random coordinates while preventing overlapping spawns using a CollisionShape2D. I am spawning the nodes one by one.

I’m using the area_entered signal to check for overlaps; if an overlap is detected, reposition the node (this has the effect that it repositions both the previously spawned node, and the new one - that’s fine). However it seems that after a while the area_entered signal stops firing for some nodes, despite the engine detecting overlapping areas. See here on the bottom-right:

overlaps

The scene is not frozen by the way, I can spawn more boxes and they start moving around again, i.e. the signal starts firing again.

The code is straightforward:

func _on_Box_area_entered(area):
    reposition()

func reposition():
    self.position = Vector2(rand_range(0, get_viewport().size.x),
                            rand_range(0, get_viewport().size.y))

Any idea why the area_entered signals stops firing despite still detecting an overlapping area?

I forgot to mention that to detect if the engine sees overlaps I’m using get_overlapping_areas() on each of the spawned boxes in _process - the result of which is displayed in the label.

dilettante | 2020-04-28 13:30

While this may not be an answer to your question, have you considered trying it a different way? It looks like each box is the same width and height, so you could keep a list of the position of all boxes on screen. Then when you randomly spawn a new one, you can perform a check to see if it overlaps with another box. It’s not the most efficient algorithm, O(n^2) runtime, as you have to check each box against every other box for each one spawned, but if you’re not spawning a large number of boxes and you notice no performance hit, it’s much simpler to do.

Trollend | 2020-04-28 18:08

I actually solved the problem of avoiding overlapping spawns by implementing an overlap check in _physics_process, but I’d still like understand why the area_entered signal fails sometimes. Whether it’s a problem with my implementation or a bug in godot, it’d be good to know for future reference.

(btw your idea would work as well, but as you said it’s probably not the most efficient approach)

dilettante | 2020-04-28 20:42

:bust_in_silhouette: Reply From: Thomas Karcher

Area_entered is only called once per enter event: If an area is moved within the colliding area without ever exiting, the signal will not be emitted again. So if an area ends up overlapping the same area as before after the random repositioning, it will not be repositioned again.

Solution: Check get_overlapping_areas ( ) in a loop and repeat repositioning as long as the result is not empty.

Thanks, that explains it. As a follow-up, where can I find it in the documentation that it only fires once per enter event? It’s not clear to me on the Area2D page. Or is this generally the case for all signals in Godot - they fire once per event?

dilettante | 2020-04-29 17:40

That’s the case for most (I guess all?) signals:

  • A timeout signal will fire exactly once after a Timer timed out
  • An area_exited signal will fire exactly once after an area exited
  • A ready signal will fire exactly once after a node is ready

So “entered” will only be fired again on reenter, with an exit in between.

Thomas Karcher | 2020-04-29 18:50