Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Tilemap, unique tiles.

Discussion in '2D' started by oen432, Feb 12, 2019.

  1. oen432

    oen432

    Joined:
    Apr 24, 2015
    Posts:
    40
    Hi,

    I have this DoorTile script
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Tilemaps;
    3. #if UNITY_EDITOR
    4. using UnityEditor;
    5. #endif
    6.  
    7. public class DoorTile : Tile
    8. {
    9.     public bool open = false;
    10.     public Sprite m_spriteOpen;
    11.     public Sprite m_spriteClosed;
    12.  
    13.     public override void RefreshTile(Vector3Int location, ITilemap tilemap)
    14.     {
    15.         tilemap.RefreshTile(location);
    16.     }
    17.  
    18.     public override void GetTileData(Vector3Int location, ITilemap tilemap, ref TileData tileData)
    19.     {
    20.         tileData.sprite = open ? m_spriteOpen : m_spriteClosed;
    21.     }
    22.  
    23. #if UNITY_EDITOR
    24.     [MenuItem("Assets/Create/DoorTile")]
    25.     public static void CreateDoorTile()
    26.     {
    27.         string path = EditorUtility.SaveFilePanelInProject("Save Door Tile", "Door_Tile", "Asset", "Save Door Tile", "Assets/Tiles");
    28.         if (path == "")
    29.             return;
    30.         AssetDatabase.CreateAsset(CreateInstance<DoorTile>(), path);
    31.     }
    32. #endif
    33. }
    And I have made Door_Closed tile, put into my palette and then added 2 doors on my Tilemap.
    Here is how I'm Opening and Closing doors using Right-Click
    Code (CSharp):
    1. private void Update()
    2.     {
    3.         mouseToGrid = worldGrid.WorldToCell(cam.ScreenToWorldPoint(Input.mousePosition) + Vector3Int.up);
    4.         mouseBlock.position = mouseToGrid;
    5.         if (Input.GetMouseButtonUp(1))
    6.         {
    7.             TileBase tile = blockTilemap.GetTile(mouseToGrid - Vector3Int.up);
    8.             if(tile is DoorTile door)
    9.             {
    10.                 door.open = !door.open;
    11.                 blockTilemap.RefreshTile(mouseToGrid - Vector3Int.up);
    12.             }
    13.         }
    14.     }
    The problem is that if I press on a DoorTile,
    open
    is changed for both DoorTile scripts. Not just for the one I pressed on. And even more, Tiles in my Assets are changed too. Why? Shouldn't tiles be unique? Is there any way to make it work?
     
    Last edited: Feb 12, 2019
  2. beanie4now

    beanie4now

    Joined:
    Apr 22, 2018
    Posts:
    311
  3. oen432

    oen432

    Joined:
    Apr 24, 2015
    Posts:
    40
    I don't want to do it that way. I would have to reference every door tile to my player. And there are going to be different types of doors. Using DoorTile with 2 sprites, Closed and Open to change based on one bool is way better and easier.
    I'll be synchronizing Tilemap with server so there is that too.
     
  4. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,503
    Tiles are ultimately ScriptableObjects. Per tile, there is one instance. So when you change open, it changes "everywhere" because there's only one instance of DoorTile per tile type. What you could do is have openDoor and closedDoor (ea. as a separate instance of Tile) and simply swap the two when the status of the door changes. You'd know whether a door is open or closed based on the tile at that position. In your Update(), you can check for reference equality to the open/closedDoor Tile to tell the status of the door in that tile.
     
  5. CheekySparrow78

    CheekySparrow78

    Joined:
    Feb 9, 2019
    Posts:
    15
    I find it really sad that Unity still haven't given us the option to make some tiles into instances. It *is* possible to create unique instances of scriptable objects, after all. However Tilemap system doesn't support it still and we have to turn to all sorts of ugly hacks. Come on, Unity, that applies to any game with tiles that have durability or even doors, chests, you can't implement those cleanly using your Tilemap! From performance point of view it is good and very logical that all the same tiles share one Scriptable object asset, but give us an *option* to make them unique!
     
  6. PuppyPolice

    PuppyPolice

    Joined:
    Oct 27, 2017
    Posts:
    116
    What you could do is to make a script that goes through all the door tiles at start and instantiate them as their own unique instance of the door tile scriptableObject that way they wont share the same states.
     
    CheekySparrow78 and eses like this.
  7. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @PuppyPolice

    "What you could do is to make a script that goes through all the door tiles at start and instantiate them as their own unique instance of the door tile scriptableObject that way they wont share the same states."

    That is exactly what I've done, and it works just fine, and isnt' that "ugly" at all.
     
  8. CheekySparrow78

    CheekySparrow78

    Joined:
    Feb 9, 2019
    Posts:
    15
    I guess that could work for things we need to be unique only at runtime. I don't see this approach working for things like containers (chests etc), that (ideally) should have their contents or other variables definable in the editor. I guess I could put tiles instantiation into a script that runs in the editor, but that already seems a bit hacky and prone to introducing unexpected bugs.
     
  9. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @CheekySparrow78

    I don't think nothing prevents you using GameObjects + sprites though? Then you can have completely unique objects, and you could still create a GameObject painting brush to place those.
     
  10. PuppyPolice

    PuppyPolice

    Joined:
    Oct 27, 2017
    Posts:
    116
    Well it is a different type of problem compared to the doors, what you could do is just have a basic gameobject over the chest tile sprite with a script that has a public list for the items you wanna add to it + all the functions you might need and just prefab that gameobject and add it over all chests and change the list of items depending on what you want it to contain. All done through the editor, once you got all components its just a 3 step process, place tile, place prefab, change list done.