How to determine if an Area2D currently intersects any part of a TileMap?

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

I want to know whether an Area2D is currently colliding with any part of my TileMap. By using the body_shape_entered and body_shape_exited signals I can detect when some part of the TileMap has entered or left the Area2D, but the problem is that receiving the signal that a body shape has exited does not tell me whether all bodies of type TileMap have exited.

I tried keeping track of the bodies that enter and exit like so:

var colliding_bodies : Array = []

func _on_body_shape_entered(body_rid, body, body_shape_index, local_shape_index):
	if body is TileMap:
		if !(body_rid in colliding_bodies):
			colliding_bodies.append(body_rid)

func _on_body_shape_exited(body_rid, body, body_shape_index, local_shape_index):
	if body is TileMap and body_rid in colliding_bodies:
		colliding_bodies.erase(body_rid)
	if colliding_bodies == []:
		# Area is no longer colliding with any tilemap bodies
           pass

but the problem here is that the body_rid is always an invalid RID for TileMap for some reason.

Is there a simpler way to just know whether an Area2D is currently colliding with any part of aTileMap? If I do have to keep track of the bodies that enter and exit, how can I do this given that the RIDs are all invalid?

Thanks!

EDIT

Another odd thing here is that the documentation for Area2D says that for TileMap collisions you can

Get the CollisionShape2D node with
body.shape_owner_get_owner(body_shape_index).

However, when I attempt to do this (after confirming body is TileMap) I get

Invalid call. Nonexistent function ‘shape_owner_get_owner’ in base ‘TileMap’

Am I misunderstanding the documentation here or is the documentation incorrect?

Incidentally, this may be related to this issue (not sure).

Maybe you can just call get_overlapping_bodies() instead?

exuin | 2023-05-01 20:41

:bust_in_silhouette: Reply From: ibrahim.semab

One way to check if an Area2D is currently colliding with any part of a TileMap is to use the get_overlapping_areas() method of the TileMap. This method returns an array of Area2D objects that are currently overlapping with the TileMap.

Here’s an example code snippet that demonstrates this:

func _process(delta):

    var overlapping_areas = $TileMap.get_overlapping_areas()

    if overlapping_areas.size() > 0:
        # Area2D is currently colliding with the TileMap
        pass
    else:
        # Area2D is not colliding with the TileMap
        pass

In this example, the get_overlapping_areas() method is called on the TileMap node every frame, and the resulting array is checked to see if it contains any elements. If the array is not empty, it means that the Area2D is currently colliding with the TileMap.

Alternatively, if you want to use the body_shape_entered and body_shape_exited signals to keep track of which TileMap bodies are colliding with the Area2D, you can try using the get_collider() method to get the TileMap object from the body parameter in the signal. Here’s an example code snippet that demonstrates this:

var colliding_bodies : Array = []

func _on_body_shape_entered(body_rid, body, body_shape_index, local_shape_index):
    if body is TileMap:
        var tilemap = body.get_collider()
        if !(tilemap in colliding_bodies):
            colliding_bodies.append(tilemap)


func _on_body_shape_exited(body_rid, body, body_shape_index, local_shape_index):
    if body is TileMap:
         var tilemap = body.get_collider()
         if tilemap in colliding_bodies:
            colliding_bodies.erase(tilemap)
    if colliding_bodies.size() == 0:
        # Area is no longer colliding with any TileMap bodies
        pass

In this example, the get_collider() method is used to retrieve the TileMap object from the body parameter in the body_shape_entered and body_shape_exited signals. The tilemap object is then used to keep track of which TileMap bodies are currently colliding with the Area2D. Note that this approach assumes that each TileMap node has a unique reference, which may not always be the case.

For the second approach, using _on_body_shape_entered, I get the error

Invalid call. Nonexistent function ‘get_collider’ in base ‘TileMap’

I also don’t see this function mentioned in the docs for TileMap. Should I be calling it on some other object?

Regarding the first approach, I don’t want to have my tileset checking on every frame, but rather just have the Area2D be able to look for collisions when active and requested by another node. Is this possible?

Godont | 2023-05-02 14:11

It looks like you just wrote the above code and didn’t connected the signal I forgot to mention that you have to connect signal

ibrahim.semab | 2023-05-02 15:28

The signal is connected. The issue here is that this method is not callable on a TileMap apparently.

Godont | 2023-05-02 15:31

Try using overlaps_shape() method as I think It is changed

ibrahim.semab | 2023-05-02 15:50