How to remove a tile at runtime?

I’m having problems deleting tiles from a
layer at runtime. Adding new tiles seems to work fine. Maybe I am missing something.

Here is a code snippet:

    public void Update()
    {
        var grid = map.GetComponentInParent<Grid>();
        var tilePos = grid.WorldToCell(transform.position);
        map.SetTile(tilePos, tile);
    }

I grab the GO in the editor and move it around to paint new tiles.

if “tile” is any tile with a sprite attached to it, the renderer uses it.

Setting to “null” does nothing.

If the tile has a sprite that is completely transparent attached to it, nothing happens either.

I’m not sure if this is a bug or expected behavior and I have to do it differently.

[Edit] When I have a tile that is transparent with some opaque elements, like a slope, the new tile gets painted ontop of the layer.

Made a GIF to demonstrate better what I am talking about. First I paint some tiles at runtime. Then I deactivate the layer “Ground” to show that I am painting on the intended layer.

1 Like

I seem to be able to remove individual tiles at runtime by setting them to null, but I think you need to target the TileMap component rather than the Grid component, e.g.

TileMap tilemap = GetComponent<TileMap> ();
tilemap.SetTile(new Vector3Int(0,0,0), null); // Remove tile at 0,0,0

However, I’ve not found a way to remove all tiles at once. There is a ClearAllVirtualTiles(), but that seems to be editor-related and does nothing to the real tiles. I could destroy and recreate the whole tilemap component, but that feels a bit hacky.

8 Likes

The “map” variable I access in my code is indeed a Tilemap layer. I’m using the grid component to calculate the tilemap cell from the world position of my gameobject. Setting to null also didn’t work for me.

Call

SetTile to null should work. I’m guessing the only thing explaining why it doesn’t work for you is that you have moved your Tilemap to different world position than your grid. Your calls to grid.WorldToCell() don’t return correct values anymore if that is the case. You need to call tilemap.WorldToCell() directly.

The Tilemap GO with Grid and all layers are still at (0/0/0). I tried calling WordToCell from tilemap directly but it didn’t make a difference.

Here is my complete setup:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Eraser : MonoBehaviour
{
    public TileMap map;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        var tilePos = map.WorldToCell(transform.position);
        map.SetTile(tilePos, null);
    }
}

I run the game and move the object around in the editor. Nothing happens. But when I modify the script to set an opague tile instead it works as expected.

When I paint a tile that has transparent parts to it, the old tile is underneath the new tile as shown in my previous GIF.

I tried all tilemap layers and they all behave the same.

I modified the Eraser script to take in a Tile (starting off with null). I made another GIF to better demonstrate what I’m getting:

The reason it is not working is that your Eraser is in Z = -88 and the default brush always paints on Z = 0.

Some context so you understand what is going on:

Tilemap is not 2D, it is 3D. All the data and APIs are in 3D coordinates. However, the current painting design is limited to 2D and we don’t really advertise that fact for UX simplicity reasons. There is no way for you to paint with default brush outside Z = 0.

In the default Rectangle layout, the rendering of any Z value is always flattened to world Z=0. Think of it as infinitely thin stack of infinite layers. You can use this for “sub-layering” if you make your levels procedurally. The sub-layers are rendered from back to front (-infinite to +infinite).

What is happening in your case is that you painted your level with default brush so the data ended up in Z=0. Then your Eraser happens to be in transform.z = -88, so the WorldToCell also returns z = -88 and you SetTile ends up in Z = -88. So when you paint with opaque, you still see it getting rendered in world Z=0, because we flatten everything.

I think this is what happening. Can’t say for 100% without having the actual project.

8 Likes

That did it! Doh. :slight_smile: Thanks!

Oh, good catch. Yeah, @der_r , I don’t know that I would’ve noticed that either until I’d pulled most of my hair out.

I know I’m 4 years late, but there is one problem with this, if you scale up the Eraser gameobject and try to “erase” a tile, you have to touch the tile with the center of the eraser, but I don’t want that. How would you do this but that it “erases” tiles on collision?

6 years later, but the answer is you need to calculate the position of the neighbour tiles(how many depends on your brush scale) and then set those to null aswell.

Non-experimental discussion in the experimental forums. Also necropost.

Please discuss the tilemap on the 2D forums.

Thanks.

Thread closed.