Search Unity

Tilemap.SetTile() not doing anything in editor script

Discussion in '2D' started by SpiralCircus, Jun 3, 2019.

  1. SpiralCircus

    SpiralCircus

    Joined:
    Feb 1, 2014
    Posts:
    34
    Hi,

    I'm trying to generate a tilemap from an editor script. I have gotten as far as generating the tile assets via script from a folder full of images. I know the position of each tile beforehand, so i want to skip the manual creation of a pallette and just instatiate and populate the tilemap in code also (since i already know what positions each tile image should be in).

    Creating the parent gameobject with the Grid component, then the child gameobject with the Tilemap component all goes fine. When I then do
    Code (CSharp):
    1. tilemap.SetTile(position, tile)
    nothing seems to happen.

    Is this supposed to fail in the editor? If not, am I missing something stupid?

    The relevant part of the code is here:
    Code (CSharp):
    1.  
    2. foreach (var tileAsset in tileAssets)
    3. {          
    4.     var path = tilePath + tileAsset.Name;
    5.     var tile = AssetDatabase.LoadAssetAtPath<TerrainTile>(path);
    6.     tilemap.SetTile(tile.position, tile);
    7. }
    8. tilemap.RefreshAllTiles();
    9.  
     
  2. Primoz56

    Primoz56

    Joined:
    May 9, 2018
    Posts:
    369
    if it doesnt do anything it would suggest your have an empty tile, otherwise it should crash

    Most likely your LoadAssetAtPath is not working correctly, likely the path is not correct (note that it must be in a folder called Resources). You can seperate the two calls and hardcode each part seperately (eg. set tile from variable in editor) and see which part breaks.
     
  3. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    I'm having this issue.. with
    SetTile(...)
    and
    SetTilesBlock(...)
    .

    1. I created a new GameObject from the constructor (completely blank object),
    2. I added Tilemap and TilemapRenderer components to it,
    3. I tried both
    SetTile(...)
    and
    SetTilesBlock(...)
    methods to set tiles with a RuleTile asset, and a Tile asset in my project.

    Nothing seems to be working beyond just the first cell at (0, 0, 0).
    The tiles don't appear, even after manual calls to
    RefreshAllTiles()
    .

    I've been looking all around the internet and the docs, and have no idea what it's doing. :/
     
    Last edited: Jul 21, 2020
  4. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    @ChuanXin any idea why setting the tiles is not working? Apologies if this is documented somewhere
     
  5. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    Ahhh no, I was probably really tired..

    Short answer: the Tilemap had no parent with a Grid component.

    ..Welp, this is embarrassing, but I'll leave this up if it helps someone as silly as me in the future. Lol
     
    vikAy99 likes this.
  6. cyclSunity

    cyclSunity

    Joined:
    Jun 10, 2020
    Posts:
    123
    Try
    :SetTile();
     
  7. A11v1r15

    A11v1r15

    Joined:
    Jun 28, 2017
    Posts:
    1
    I'm having this problem:

    Code (CSharp):
    1.  
    2.     private void OnGUI()
    3.     {
    4.         _baseTile = EditorGUILayout.ObjectField("Base Tile", _baseTile, typeof(Tile), false) as Tile;
    5.         _map = EditorGUILayout.ObjectField("Map to change", _map, typeof(Tilemap), true) as Tilemap;
    6.         if (GUILayout.Button("Change‼"))
    7.         {
    8.             foreach(Vector3Int position in _map.cellBounds.allPositionsWithin)
    9.             {
    10.                 if (_map.HasTile(position))
    11.                 {
    12.                     _map.SetTile(position, _baseTile);
    13.                     _map.RefreshTile(position);
    14.                 }
    15.             }
    16.         }
    17.     }
    When I click the button, it changes all tiles, as expected, but there's no change in the scene, saving does nothing and if I go out of the scene and back, it is the same way it was before
     
  8. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    In your example, after Line 13, you can mark the scene dirty so the Unity editor knows it's been modified, and a Ctrl +S (afterwards) would save the scene, attempting to close the scene would ask you if you'd like to save, etc.

    With
    using UnityEditor.SceneManagement;
    at the top of your script,

    you can then use
    EditorSceneManager.MarkSceneDirty(_map.gameObject.scene);
    right after Line 13.
     
    A11v1r15 likes this.
  9. theforgot3n1

    theforgot3n1

    Joined:
    Sep 26, 2018
    Posts:
    208
    I'm having this exact problem. The scene does not change, the tilemap remains the same. I'm using an Editor window to perform the tilemap manipulation inside of a prefab scene. It looks like this

    upload_2022-12-10_23-54-1.png

    The only way to swap the tiles (I'm trying to remove all instanced of MutedGrassRuleTile to null) looks to be to manually remove it. Dunno why.

    This is my code


    Code (CSharp):
    1.  
    2.            ...
    3.  
    4.             Rect rect = EditorGUILayout.GetControlRect(true, 60);
    5.             if (GUI.Button(rect.AlignCenter(300, 50),
    6.                     "Swap tiles"))
    7.             {
    8.                 Undo.RecordObject(this.tilemap, "Swapping tiles in tilemap");
    9.                 BoundsInt bounds = this.tilemap.cellBounds;
    10.                 TileBase[] allTiles = this.tilemap.GetTilesBlock(bounds);
    11.                 for (int x = 0; x < bounds.size.x; x++)
    12.                 {
    13.                     for (int y = 0; y < bounds.size.y; y++)
    14.                     {
    15.                         TileBase tile = allTiles[x + (y * bounds.size.x)];
    16.                         if (tile == this.current)
    17.                         {
    18.                             this.tilemap.SetTile(new Vector3Int(x, y, 0), this.target);
    19.                             Debug.Log($"Replaced tile at ({x}, {y}) with {tile.name}");
    20.                         }
    21.                     }
    22.                 }
    23.  
    24.                 EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
    25.             }
    26.  
    27.            ...
     
  10. theforgot3n1

    theforgot3n1

    Joined:
    Sep 26, 2018
    Posts:
    208
    After a year or so I stumbled upon this same thread and tried to solve the issue with SetTile. We did solve it. The solution was not to use SetTile and instead use SwapTile for swapping out existing things in the Editor script. This is not really a solution to SetTile... sorry folks, but it worked for us. :)