Setting a tile to null results in an error "Destroying object multiple times"

I spent quite a while on this problem and it’s starting to bug me out. It’s not crashing the game or anything, just a little annoying, but the basic gist of it is that I have a custom tile with associated game object:

public class GrassTile : TileBase
{
    public GameObject tileGameObject;
    public Sprite sprite;

    public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
    {
        tileData.gameObject = tileGameObject;
        tileData.sprite = sprite;
    }
}

So far so good, and here’s the script for the tile object itself:

public class GrassTileObject : MonoBehaviour
{
    private GameObject _objectOnTile;
    private Tilemap _tilemap;

    private void Start()
    {
        _tilemap = FindObjectOfType<Tilemap>();
    }
    public GameObject ObjectOnTile => _objectOnTile;
    public void SetObjectOnTile(GameObject objectOnTile)
    {
        _objectOnTile = objectOnTile;
    }
    private void OnDestroy()
    {  
        _tilemap.SetTile(_tilemap.WorldToCell(transform.position), null);    
    }
}

OnDestroy() is triggered when the field _health is <= 0:

public class Health : MonoBehaviour
{
    [SerializeField] private int _health;
    public int HealthPoints => _health;

    public void TakeDamage(int damage)
    {
        _health -= damage;
        if (_health <= 0)
        {
            EventManager.Instance.TriggerEntityDiedEvent(GetComponent<Entity>());
            Destroy(gameObject);
        }
    }
}

Now the problem is that for some reason whenever the associated tile object is destroyed, Unity is insisting that I’m destroying the object multiple times:

Destroying object multiple times. Don’t use DestroyImmediate on the same object in OnDisable or OnDestroy.
UnityEngine.Tilemaps.Tilemap:SetTile (UnityEngine.Vector3Int,UnityEngine.Tilemaps.TileBase)
GrassTileObject:OnDestroy () (at Assets/Scripts/GrassTileObject.cs:27)

If I comment out the “_tilemap.SetTile(_tilemap.WorldToCell(transform.position), null);” line, the error is gone. I’m thinking the reason could be that when the tile is set to null, the associated game object is destroyed, but I couldn’t find any information on that, so I’m just blind guessing.

Any ideas on how to fix this?

This is a declaration for the script(component) of “Tilemap”.

here you only ask for the gameObject component, not it’s script.

I would assume this should fix your error:
_tilemap = FindObjectOfType<Tilemap>().GetComponent<TileMap>();

However you should have a better way of getting this object, than to use find object of type, but first things first, just fix your error. :slight_smile:

Uh, no, FindObjectOfType<T> returns the first instance of a component found in the scene, and has nothing to do with this error.

@Dowlgrett I would check if the event is being raised multiple times.

2 Likes

Destroy doesn’t destroy the object immediately, it puts it in a queue to be destroyed at the end of the frame. In Unity, that means that managed pointers/references to the object don’t get set to null straight away, other objects can still find it via GetComponent() et all, and so on.

My first guess would be that it’s taking damage multiple times at once, resulting in Destroy getting called multiple times. If so, an easy way to get around it could be to early exit if health is already <= 0.

1 Like

I tried changing Health component a bit like so, but still it gives me the same error:

private bool isDestroyed;

    public void TakeDamage(int damage)
    {
        _health -= damage;

        if (_health <= 0 && !isDestroyed)
        {
            EventManager.Instance.TriggerEntityDiedEvent(GetComponent<Entity>());
            Destroy(gameObject);
            isDestroyed = true;
        }
    }

That was just my first guess, we don’t have any details about what’s going on.

Do you have any other calls to Destroy() in your code? I’d put break points on them and see when they’re getting called for what.