The Godot Q&A is currently undergoing maintenance!

Your ability to ask and answer questions is temporarily disabled. You can browse existing threads in read-only mode.

We are working on bringing this community platform back to its full functionality, stay tuned for updates.

godotengine.org | Twitter

0 votes

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?

in Engine by (15 points)

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.

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.

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)

1 Answer

+2 votes
Best answer

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.

by (1,732 points)
selected by

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?

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.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.