Programmatic Creation of Area2D and Unintended Overlaps with Character

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

I’m new to Godot, and came across an issue. Maybe I’m going about this the wrong way or I’m unaware of something.

I’m procedurally generating levels/maps. I display one “room” of the level at a time. Each room is rendered “top down” using a TileMap.

I have door triggers in the form of Area2D-based scenes with a CollisionShape2D child. I spawn them at the appropriate locations based on the room. I do this by converting what would be the tilemap location to the world location.

A lot of the time, everything works just fine: When my character overlaps with one of the above door triggers, I clear the TileMap and the Area2D triggers, and render the new room as above. Then my character goes about his merry way.

However, a non-trivial percentage of the time, the character seems to immediately set off one of the newly-spawned door triggers in the new room.

I do the following when a new room is supposed to be rendered:

  • Clear the TileMap and destroy/free the old triggers.
  • Set the location of the character to be someplace off-screen.
  • Create the TileMap.
  • Create the door triggers and wire them to the “body_entered” signal.
  • Set the location of the character to be someplace not near any door triggers.

And yet, I’ve confirmed that, despite the above, the character sometimes immediately overlaps one of the door triggers, and I can’t figure out why. Best guess is that the location data of the character is stale when the new door triggers are spawned, possibly as part of a race condition. I’ve even tried changing the collision bitmask/layer of the character to before and after creating the door triggers, but, it doesn’t correct the the situation.

I’ve tried examining the location of the colliding body (i.e. the KinematicCharacter2D), and while I’ve verified it is, in fact, the character, I’m guessing that because the “body” argument of the “body_entered” signal is passed by reference, that by the time I examine the location of the character, it’s at the appropriate location (and nowhere near any of the triggers).

Am I going about this the wrong way? Or does any of this sound like something a Godot noob would do?

Thanks in advance.

While I’m not sure what’s causing this bug, a better way to do this that might solve it is to instance the character in different levels as opposed to redrawing the tilemap every time.
The way to do this is saving each level (or tilemap configuration) as its own scene then running the following code on your change scene triggers:

var bodies = get_overlapping_bodies()
for body in bodies:
if body.name == "Player":
    get_tree().change_scene("file_path_to_next_level")

of course, this is a little outdated, and I personally would just use layers and masks as opposed to body.name.

you can find a full explanation here: https://www.youtube.com/watch?v=KzLfi0r4Muw&list=PL9FzW-m48fn2jlBu_0DRh7PvAt-GULEmd&index=4

DigitalDrako | 2020-06-13 20:31

Thanks for the reply. I’ll be sure to take a look at the video.

So, as my levels are procedurally generated, would I have to instance a new TileMap into a new scene, configure it along with any Area2D triggers that are needed in the scene, save it to disk, and then subsequently load it when changing rooms? I could give that a try.

Although, I’d still be interested in knowing why the above is happening as I worry I might be doing something not very idiomatic and could run into a similar issue manifested differently.

btysgtmajor | 2020-06-13 21:49

After digging more, I’m now 95% convinced it’s because any attributes of the character that I change immediately before spawning the new Area2D triggers are not immediately visible/available to the physics engine (or whatever is determining overlaps), and, as such, if a new trigger is created in essentially the same location as one of the triggers from the previous room, an overlap signal occurs.

Looking at the “body” position from within the event, it contains the proper position/attributes, so it’s rather misleading in that respect.

Any advice on how to deal with this kind of latency?

btysgtmajor | 2020-06-16 04:51