Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Correct way to destroy scripted tile in Tilemap on collision

Discussion in 'Scripting' started by Nomadjackalope, Oct 23, 2018.

  1. Nomadjackalope

    Nomadjackalope

    Joined:
    Jul 12, 2016
    Posts:
    16
    I have created a script that extends TileBase and have created a tile using that. It has a gameObject on it following https://docs.unity3d.com/ScriptReference/Tilemaps.TileBase.StartUp.html where I drop a prefab on the tile before putting it in the palette and painting.

    There is a ball with collider and rigidbody2d above a tile and it falls to break the tile but I run into an error;

    When my ball collider hits the tile and launches the following OnCollisionEnter2D
    Code (CSharp):
    1. void OnCollisionEnter2D(Collision2D collision) {
    2.         // This code came from https://github.com/Unity-Technologies/2d-techdemos in the brick scripts
    3.        
    4.         Vector3 hitPosition = Vector3.zero;
    5.         if (tilemap != null)
    6.         {
    7.             foreach (ContactPoint2D hit in collision.contacts)
    8.             {
    9.                 hitPosition.x = hit.point.x - 0.01f * hit.normal.x;
    10.                 hitPosition.y = hit.point.y - 0.01f * hit.normal.y;
    11.  
    12.                 // This line in particular is not working
    13.                 tilemap.SetTile(tilemap.WorldToCell(hitPosition), null);
    14.             }
    15.         }
    16. }
    I get the error

    Code (CSharp):
    1. Destroying GameObjects immediately is not permitted during physics trigger/contact, animation event callbacks or OnValidate. You must use Destroy instead.
    2. UnityEngine.Tilemaps.Tilemap:SetTile(Vector3Int, TileBase)
    3. TilemapManager:OnCollisionEnter2D(Collision2D) (at Assets/Scripts/TilemapManager.cs:26)
    So I tried
    Destroy(tilemap.GetInstantiatedObject(tilemap.WorldToCell(hitPosition)));


    and then setting the tile to null but that still gives the error. I even tried moving the nulling code into the OnDestroy of the ball but that still gives the same error.

    How am I supposed to use the GameObject in a script that extends TileBase and make it destructible?

    The attached UnityPackage is my setup
     

    Attached Files:

  2. theuncas

    theuncas

    Joined:
    Feb 21, 2015
    Posts:
    22
  3. TuckerFlynn

    TuckerFlynn

    Joined:
    May 18, 2015
    Posts:
    10
    I know I'm necro-ing an old post here, but I was having the same issue with removing tiles with attached gameobjects and couldn't find a posted solution. In the end the solution that worked for me was destroying the gameobject and setting the tile to null like in the brick breaker demo, but from within a coroutine:

    Code (CSharp):
    1. IEnumerator DelayedDestroy()
    2.     {
    3.         yield return new WaitForEndOfFrame();
    4.  
    5.         Destroy(this.gameObject);
    6.         DestroyTile();
    7.     }
    8.  
    9. void DestroyTile ()
    10.     {
    11.         Tilemap tilemap = GetComponentInParent<Tilemap>();
    12.         Vector3Int pos = Vector3Int.FloorToInt( transform.position );
    13.         tilemap.SetTile(pos, null);
    14.     }
    Where the coroutine is started within an OnTriggerEnter2D method. As far as I understand, setting a tile to null with Tilemap.SetTile() tries to immediately destroy the attached gameobject which isn't allowed within OnTriggerEnter so this solution circumvents this issue by waiting until the next frame to clear the tile.
     
    Nomadjackalope likes this.