Animating specific tiles in a tilemap

Hi,

In my game, I want to have platforms that crumble as the player walks over them, eventually dropping the player into the nether regions. However, I can’t find anything in the tilemap that allows this. Animated tiles, yes, but not an individual tile at specified times. Eventually, I wrote this script. Am I re-inventing the wheel?

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

public class DestructibleTiles : MonoBehaviour
{
    [SerializeField] TileBase[] floorTiles;
    [SerializeField] float timeToUpdate;

    bool isPlayerTouching = false;
    Tilemap tilemap = null;

    Dictionary<Vector3Int, TileTracker> currentTiles = new Dictionary<Vector3Int, TileTracker>();
    Dictionary<Vector3Int, TileTracker> tileLookup = new Dictionary<Vector3Int, TileTracker>();

    void Awake()
    {
        tilemap = GetComponent<Tilemap>();
    }

    void Update()
    {
        if (currentTiles.Count == 0) { return; }
        if (isPlayerTouching)
        {
            UpdateTouchedTiles();
        }
    }

    void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Player") &&
            collision.collider.GetType() == typeof(BoxCollider2D))
        {
            isPlayerTouching = true;
            UpdateContacts(collision);
        }
    }

    void OnCollisionStay2D(Collision2D collision)
    {
        if (isPlayerTouching)
        {
            currentTiles.Clear();
            UpdateContacts(collision);
        }
    }

    void OnCollisionExit2D(Collision2D collision)
    {
        currentTiles.Clear();
        isPlayerTouching = false;
    }

    private void UpdateContacts(Collision2D collision)
    {
        foreach (ContactPoint2D hit in collision.contacts)
        {
            Vector3 hitPosition = Vector3.zero;
            hitPosition.x = hit.point.x - 0.1f;
            hitPosition.y = hit.point.y - 0.1f;
            Vector3Int pos = tilemap.WorldToCell(hitPosition);
            TileBase newTile = tilemap.GetTile(pos);
            if (newTile != null)
            {
                currentTiles[pos] = new TileTracker();
            }
        }
    }

    private void UpdateTouchedTiles()
    {
        foreach (Vector3Int pos in currentTiles.Keys)
        {
            if (!tileLookup.ContainsKey(pos))
            {
                tileLookup[pos] = new TileTracker();
            }

            UpdateTile(pos);
        }
    }

    private void UpdateTile(Vector3Int pos)
    {
        TileTracker tracker = tileLookup[pos];

        tracker.SetElapsedTime(tracker.GetElapsedTime() + Time.deltaTime);

        if (tracker.GetElapsedTime() > timeToUpdate)
        {
            UpdateTile(pos, tracker);
        }
    }

    private void UpdateTile(Vector3Int pos, TileTracker tracker)
    {
        int currentIndex = tracker.GetIndex() + 1;
        if (currentIndex < floorTiles.Length)
        {
            ReplaceTile(pos, tracker, currentIndex);
        }
        else
        {
            EraseTile(pos);
        }
    }

    private void ReplaceTile(Vector3Int pos, TileTracker tracker, int currentIndex)
    {
        TileBase newTile = floorTiles[currentIndex];
        tilemap.SetTile(pos, newTile);
        tracker.SetIndex(currentIndex);
        tracker.SetElapsedTime(0);
    }

    private void EraseTile(Vector3Int pos)
    {
        tilemap.SetTile(pos, null);
    }
}

public class TileTracker
{
    int index = 0;
    float elapsedTime = 0;

    public int GetIndex() { return index; }
    public float GetElapsedTime() { return elapsedTime; }

    public void SetIndex(int index)
    {
        this.index = index;
    }

    public void SetElapsedTime(float value)
    {
        elapsedTime = value;
    }
}

Privacy & Terms