Search Unity

Tiles customization, additional data and functions (Tilemaps)

Discussion in '2D' started by Dried09, Jan 6, 2018.

  1. Dried09

    Dried09

    Joined:
    Jan 2, 2017
    Posts:
    7
    Hi there! Working now on 2d top down project (nes's battlecity-like) and decided to using useful new feature - Tilemaps from 2017.2 update. Everything was going well, but I'm stucked with implement destructuble tiles. I mean not just removing tiles from tilemap (I'm ok with it), I need to store durability value of each wall tile, which may be various depending on the wall material. And also I need additional functions to control durability, tile destruction and fx (dust particles, sounds). On the whole, I need all these useful possibilities that gives me a regular GameObject. But I know that tiles don't inherit MonoBehaviour class and I can't using it so.
    What I alredy tried:
    1) creating custom tile class by inherit Tile class and add necessary variables and functions.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Tilemaps;
    5. using UnityEditor;
    6.  
    7. public class DestructableTile : Tile {
    8.  
    9.     [SerializeField]
    10.     public Sprite destructedTile;
    11.  
    12.     [SerializeField]
    13.     public int durability = 3;
    14.  
    15.     /*
    16.     public override void RefreshTile(Vector3Int location, ITilemap tileMap)
    17.     {
    18.         base.RefreshTile (location, tileMap);
    19.     }*/
    20.  
    21.     public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
    22.     {
    23.         base.GetTileData (location, tileMap, ref tileData);
    24.         if (durability <= 0)
    25.         {
    26.             tileData.sprite = destructedTile;
    27.             tileData.colliderType = ColliderType.None;
    28.             //RefreshTile (location, tileMap);
    29.         }
    30.     }
    31.  
    32.     public void Damage()
    33.     {
    34.         durability -= 1;
    35.         Debug.Log ("Durability is now: " + durability);
    36.     }
    37.  
    38.     #if UNITY_EDITOR
    39.     [MenuItem("Assets/Create/Destructable Tile")]
    40.     public static void CreateAnimatedTile()
    41.     {
    42.         string path = EditorUtility.SaveFilePanelInProject("Save Destructable Tile", "New Destructable Tile", "asset", "Save Destructable Tile", "Assets");
    43.         if (path == "")
    44.             return;
    45.  
    46.         AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<DestructableTile>(), path);
    47.     }
    48.     #endif
    49. }
    50.  
    It takes effect even in editor mode and even on tile palette window! Also it doesn't refresh itself, and when I force refresh (commented code) - Unity editor is deadly freezes. Fail.

    2) creating custom tile class by inherit TileBase class. I think rewriting all default functional for few small additions it's too much. Also fail.

    3) seems like tiles data storing in tilemap's variable TileData, which is a struct. I can't find a way how to customize it, structs is not able to inherit other structs...

    4) downloaded a 2d-extras assets from here https://github.com/Unity-Technologies/2d-extras
    Among other it contains GridInformation script, I guess it may be solution of my problem, but it has no any comments\docs\references about how to use it. Only info, which say's that script "stores and provides information".

    Can someone help me?
     
  2. lab6

    lab6

    Joined:
    Jan 1, 2018
    Posts:
    1
    You can spawn gameobjects through tiles. TileData has a "gameObject" property, assign some prefab to it in GetTileData method and it will be spawned when you place a tile. This way you will have fully functional prefabs as tiles. The only problem i couldn't solve with it is that you can't really select prefabs spawned this way in editor, so it's not possible to change their individual properties (for example durability).
     
  3. Dried09

    Dried09

    Joined:
    Jan 2, 2017
    Posts:
    7
    Thanks, lab6! I missed this thing in scripting reference. It looks like a way to do all this stuff what I need.
    I alredy made few scripts with additional logic, add it to gameobject, and put it all to Instanced GameObject field of my custom tile. It's ok with impossibility to change value in inspector, I can make simle custom inspector.
    Now I have another problem - changes in one separated tile are applying to all other instances. Furthermore, all tile instances saves their values even when close play mode.
    New tilemaps API has is quite confusing way to control tiles state. I know tilemaps don't creating a copy of tile-object for each drawed tile, tiles in assets is some king of config, and all changes with tile in scripts will affect all it's copies. Except standart functions like SetTile() and others. So, how I can access exactly needed component?
    Below part of my scripts:
    Shell script, which controls collision between shell collider and tile and handle it

    Code (CSharp):
    1. void OnCollisionEnter2D(Collision2D collision)
    2.     {
    3.         if (collision.gameObject.tag != "Player" && collision.gameObject.tag != "Shell")
    4.         {
    5.             Vector3 hitPos = Vector3.zero;
    6.  
    7.             if (collision.contacts.Length > 0)
    8.             {
    9.                 hitPos.x = collision.contacts[0].point.x;
    10.                 hitPos.y = collision.contacts[0].point.y;
    11.  
    12.                 if (GameManager.Instance.walls.GetTile (GameManager.Instance.walls.WorldToCell (hitPos)) is DestructableTile)
    13.                 {
    14.                     //Get tile instance
    15.                     DestructableTile dtile = GameManager.Instance.walls.GetTile (GameManager.Instance.walls.WorldToCell (hitPos)) as DestructableTile;
    16.                     dtile.gameObject.GetComponent<DestructableTileComponent>().Damage(1);
    17.                 }
    18.             }
    19.  
    20.             Instantiate (ReferencePool.Instance.explosionPrefab, transform.position, Quaternion.identity);
    21.             Destroy (gameObject);
    22.         }
    23.     }
    Instanced GameObject script, placed on my custom tile (DestructableTile/Instanced GameObject/%ThisScript%)

    Code (CSharp):
    1. public class DestructableTileComponent : MonoBehaviour {
    2.  
    3.     public int durability = 3;
    4.  
    5.     public void Damage(int damageValue)
    6.     {
    7.         durability -= damageValue;
    8.         Debug.Log (durability);
    9.     }
    10. }
    Thank you in advance!
     
    CheekySparrow78 likes this.
  4. djpronta

    djpronta

    Joined:
    May 19, 2018
    Posts:
    1
    Did you figure this out? Im having the same problem now where I want individual instances of the tile to have custom variables. Problem is when I change one of them it changes all of them.
     
  5. Dried09

    Dried09

    Joined:
    Jan 2, 2017
    Posts:
    7
    Did I know a way how to do this - yes. Did this way acceptable for me - no.
    Several months ago, when I searched for answer, I found similar topic on Answers and join discussion.
    See the link below for all, what I have know for now.
    https://answers.unity.com/questions/1434719/i-am-using-the-new-tilemap-feature-in-unity-2017-h.html
     
    CheekySparrow78 likes this.
  6. Meneliki_

    Meneliki_

    Joined:
    Feb 7, 2020
    Posts:
    10
    Hi, I'm not real clear on how you managed to reference the instanced object created by the tile?
    Thanks
     
  7. PuppyPolice

    PuppyPolice

    Joined:
    Oct 27, 2017
    Posts:
    116
    I mean it should not be that hard to grab the GameObject of a tile,
    either just grab it from the tilemap with getTile(vector3int position).gameObject should work.
    if you want to you can use custom tiles, you can just alter the startup function
    https://docs.unity3d.com/ScriptReference/Tilemaps.TileBase.StartUp.html and send a reference to a script to hold the reference to it for when you need to alter it, so it does it automatically

    edit: Come to think about it should be possible, to add a prefab GameObject to a custom tile and instantiate it in startup and replace tile.gameobject with the prefab, have not tried it but seems plausible..
     
    Last edited: Feb 7, 2020
  8. Voidsay

    Voidsay

    Joined:
    Jun 20, 2020
    Posts:
    6
    I found a guy on YouTube that made good tutorials on tile map data. He uses the manager approach and just stores everything in a custom dictionary.

    The first one is for storing static data. Good for terrain modifiers, directions and movement speed. Not exactly what op asked for, but I use it and someone might find it useful as well.


    The second one is for storing data for individual tiles. This one might actually fit op's problem better, since changes wont affect the copies and reset properly. You're still going to have to make a custom script to "predamage" tiles/give them truly unique values.


    Edit: if your cookie settings block the links here they again:

    https://www.youtube.com/watch?v=XIqtZnqutGg
    https://www.youtube.com/watch?v=nRFZDmThbdE
     
    rizartic and Aristico305 like this.