Detecting CharacterBody2D entering specific tiles in a TileMap

Godot Version

v4.3.stable.official [77dcf97d8]

Question

Hello everyone,
I’m building a simple platformer to get familiar with Godot’s mechanics.

I have a tileset I’m using to draw platforms and my character walks on them just fine. Now I would like to add areas of the map with special behaviors, like traps, teleport etc.

The first one I’m adding is a door, which represents the exit of the level. I would like my character to be able to walk in front of it and then, based on player input, “enter” the door and proceed to the next level.

My door is a tile and I placed it on a TileMapLayer. I didn’t add any collision to the first physics layer that all the platforms are on, so the character can walk just in front of it. But I’m struggling to “catch” when the character overlaps with the door.

I was hoping to use a similar mechanism to that of detecting body_entered on an Area2D with collision shape, which is very easy to use and scalable for similar tiles.

I tried adding a a new physics layer to the TileMapLayer and using a mask that doesn’t collide with the player. Still I can’t find how to trigger executing tile-specific code in the TileMapLayer.

The only way I was able to make it work has been to place in _physics_process a call to get_cell_tile_data with the position of the character2d and then checking for a custom data string that I set to “Door” for that specific tile.
It seems like a messy way to do it and it requires knowing the position of the CharacterBody2D at all times, which is not scalable if I’d like the effect to apply to many moving bodies.

Thanks for reading so far, any suggestions?

I’ve done this two ways. One was to draw Area2D and CollisionShape2D on the map but this ended up being a pain to manage and inflexible.

I ended up creating a new scene (for teleporting) with a single sprite from the tilemap. That way I could copy and paste it around the map and change the behaviour depending on which item the player was on.

Thanks pdhales72, the Area2d approach works, but it requires creating a new scene for every tile/behaviour. It’d be more efficient to be able to define the behavior of each tile within the TileMap.

If you even find a nice way to do this, let me know. :smile:

Add a custom data layer to the tileset resource, this can be any data you like. Retrieving this data from get_cell_tile_data. You can detect which tile the player is over by converting their position to tilemap coordinate like so, assuming your custom data is a string/scene path.

var tile_coord = tilemap.local_to_map(tilemap.to_local(global_position))
var tile_data = tilemap.get_cell_tile_data(tile_coord)
if tile_data:
    var custom_data = tile_data.get_custom_data("door_location")
    get_tree().change_scene_to_file(custom_data)
2 Likes

Thanks gertkeno, I agree this is the best solution at the moment.

I imagine this is a relatively common use case and it could be worth adding functionality to the engine to have an event that is triggered when the position of a body overlaps a specific tile.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.