How do I remove a tile from a scene programmatically? I have tried the following to no avail:

func _physics_process(_delta):


    velocity = move_and_slide(velocity, Vector2.UP)

    for i in get_slide_count():
        var collision = get_slide_collision(i)
        if collision.collider.name == "MysteryBox":

func remove_tile(position):
    var tilemap= get_parent().get_node("Tilesets/MysteryBox")
    tilemap.set_cell(position.x, position.y, -1)

I can detect the MysteryBox when the player collides with it, but the remove function is not removing the tile the player touched from the scene. Thanks in advance! Godot version 3.4.2

  • \$\begingroup\$ Does calling tilemap.get_cell(position.x, position.y) inside remove_tile return the tile you are expecting to modify? I recall different coordinate behavior for set_cell vs set_cellv ... could you be pointing it at something other than what you intend? \$\endgroup\$
    – yoozer8
    Mar 4, 2022 at 18:38
  • \$\begingroup\$ It's returning INVALID_CELL... can you suggest an approach for what I want to do? \$\endgroup\$ Mar 4, 2022 at 18:43

1 Answer 1


You need to convert the position from global coordinates (which is what you get in a KinematicCollision or KinematicCollision2D such as the one returned by get_slide_collision) to the coordinates of the TileMap.

What I said above can be accomplished like this:

var local_position:Vector2 = tilemap.to_local(position)

However, you also want the position in tiles. Not pixels. Which you could do using the size of a cell:

var local_position:Vector2 = tilemap.to_local(position)
var cell_position:Vector2 = local_position/tilemap.cell_size

Or alternatively yet, do it like this:

var local_position:Vector2 = tilemap.to_local(position)
var cell_position:Vector2 = tilemap.world_to_map(local_position)

And now you know what world_to_map does and why you would want to use it. There is also a map_to_world that does the opposite transformation.

If I understand correctly you want to remove the tile that your KinematicBody2D collided with. So you are taking the position of the collision. However, the position of the collision is not inside the tile.

To fix that, you can offset the position in the opposite direction of the normal of the collision (i.e. inwards into whatever it collided with):

var tilemap:TileMap = collision.collider as TileMap
var local_position:Vector2 = tilemap.to_local(collision.position)
var cell_position:Vector2 = tilemap.world_to_map(local_position)
cell_position -= collision.normal

Then cell_position should be inside the correct tile.

  • \$\begingroup\$ I am getting "Parser Error: The assigned value doesn't have a set type; the variable type can't be inferred." from your second code example. Taking the colons out, the code runs but still returns INVALID_CELL. \$\endgroup\$ Mar 4, 2022 at 19:15
  • \$\begingroup\$ @KeithR.Davis I can tell you that local_position and cell_position should be Vector2, you can either specify it (i.e. example local_position:Vector2 = …) or you can remove the : which leaves the variable as variant. Turns out it could not figure out the type, because it didn't know the Node from get_node is a TileMap. You could do var tilemap= get_parent().get_node("Tilesets/MysteryBox") as TileMap is you wish. About INVALID_CELL, it means there is no tile there, are you sure there is one? Edit: I think I see what it is, I'll update the answer. \$\endgroup\$
    – Theraot
    Mar 4, 2022 at 19:29
  • \$\begingroup\$ Had to subtract -1 from the cell_position.y to get the tile above the player and then it worked! \$\endgroup\$ Mar 4, 2022 at 19:37
  • \$\begingroup\$ @KeithR.Davis That is the idea, except you are now assuming that the collision is always in that direction. There is a general solution. Edit: added to the answer. \$\endgroup\$
    – Theraot
    Mar 4, 2022 at 19:38
  • \$\begingroup\$ Thanks so much for your help! Working great! \$\endgroup\$ Mar 4, 2022 at 19:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .