Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

How to remove a tile at runtime?

Discussion in '2D Experimental Preview' started by der_r, Jun 6, 2016.

Thread Status:
Not open for further replies.
  1. der_r

    der_r

    Joined:
    Mar 30, 2014
    Posts:
    259
    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:

    Code (CSharp):
    1.     public void Update()
    2.     {
    3.         var grid = map.GetComponentInParent<Grid>();
    4.         var tilePos = grid.WorldToCell(transform.position);
    5.         map.SetTile(tilePos, tile);
    6.     }
    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.

     
    Last edited: Jun 6, 2016
    DBarlok likes this.
  2. Sir-Spunky

    Sir-Spunky

    Joined:
    Apr 7, 2013
    Posts:
    132
    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.

    Code (csharp):
    1. TileMap tilemap = GetComponent<TileMap> ();
    2. 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.
     
  3. der_r

    der_r

    Joined:
    Mar 30, 2014
    Posts:
    259
    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.
     
  4. keely

    keely

    Joined:
    Sep 9, 2010
    Posts:
    967
    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.
     
  5. der_r

    der_r

    Joined:
    Mar 30, 2014
    Posts:
    259
    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:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Eraser : MonoBehaviour
    6. {
    7.     public TileMap map;
    8.     // Use this for initialization
    9.     void Start()
    10.     {
    11.  
    12.     }
    13.  
    14.     // Update is called once per frame
    15.     void Update()
    16.     {
    17.         var tilePos = map.WorldToCell(transform.position);
    18.         map.SetTile(tilePos, null);
    19.     }
    20. }








    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.
     
  6. der_r

    der_r

    Joined:
    Mar 30, 2014
    Posts:
    259
    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:

     
  7. keely

    keely

    Joined:
    Sep 9, 2010
    Posts:
    967
    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. der_r

    der_r

    Joined:
    Mar 30, 2014
    Posts:
    259
    That did it! Doh. :) Thanks!
     
  9. Xepherys

    Xepherys

    Joined:
    Sep 9, 2012
    Posts:
    204
    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.
     
  10. SilverFox13

    SilverFox13

    Joined:
    Mar 24, 2018
    Posts:
    1
    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?
     
  11. zevonbiebelbrott

    zevonbiebelbrott

    Joined:
    Feb 14, 2021
    Posts:
    122
    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.
     
  12. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,761
    Non-experimental discussion in the experimental forums. Also necropost.

    Please discuss the tilemap on the 2D forums.

    Thanks.

    Thread closed.
     
Thread Status:
Not open for further replies.