Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice
  2. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  3. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Runtime generation and tilemap collider

Discussion in '2D Experimental Preview' started by Sir-Spunky, Jan 5, 2017.

  1. Sir-Spunky

    Sir-Spunky

    Joined:
    Apr 7, 2013
    Posts:
    132
    Hi.

    I'm generating my tilemap at runtime by using Tilemap.SetTile(), and I'm using raycasts for collision detection, which works just fine. I managed to re-generate the tilemap collider by disabling and enabling the Tilemap Collider 2D component, although I would prefer if there was a dedicated method for doing this (I couldn't find one).

    This all works fine when running within Unity. However, when I build the project for Windows and run the exe-file, my character just falls through the platform as if the tilemap collider didn't exist. I also get the following error message, which might be related:

    "Sprite outline generation failed - could not read texture pixel data. Did you forget to make the texture readable?"

    Do you have any idea what's causing this?


    Here's the script I use to generate the platform:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.Tilemaps;
    6.  
    7. public class DrawTilemap : MonoBehaviour {
    8.  
    9.     public Tilemap tilemap; // The Tilemap component on the gameobject where the platform should be drawn
    10.     public TileBase tile; // The tile sprite (TileBase) to be used to draw the platform
    11.  
    12.     // Use this for initialization
    13.     void Start () {
    14.         GenerateWorld ();
    15.     }
    16.  
    17.     void GenerateWorld () {
    18.         // Create a 10x10 platform of tiles
    19.         for (int x = -5; x < 5; x++) {
    20.             for (int y = 0; y > -10; y--) {
    21.                 tilemap.SetTile(new Vector3Int(x,y,0), tile);
    22.             }
    23.         }
    24.  
    25.         RefreshCollider ();
    26.     }
    27.  
    28.     void RefreshCollider () {
    29.         // Update the tilemap collider by disabling and enabling the TilemapCollider2D component. This is the only solution I found to refresh it during runtime.
    30.         tilemap.gameObject.GetComponent<TilemapCollider2D>().enabled = false;
    31.         tilemap.gameObject.GetComponent<TilemapCollider2D>().enabled = true;
    32.     }
    33. }
     
    dougn7 likes this.
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,266
    There's a bug in the TilemapCollider2D not regenerating the tile collision shape when the tile changes which will be fixed. Disabling/Enabling obviously regenerates the whole tilemap as a workaround but as you probably know is expensive.

    As to the other issue; I'm not sure what's going on there so I'll pass it onto the 2D guys involved in the sprite stuff.
     
    Sir-Spunky likes this.
  3. Sir-Spunky

    Sir-Spunky

    Joined:
    Apr 7, 2013
    Posts:
    132
    Thanks for the info!

    Yes, I noticed it was quite expensive, but physics usually are, so I was planning to split the map into chunks of multiple Tilemap gameobjects so I only have to update the collider on a smaller area if the player changes one tile.

    Something that would help is a feature that automatically splits the collider into multiple chunks if requested, with the possibility to specify chunk size yourself, so you can choose if you want to optimize draw calls (larger chunks) or runtime generation (smaller chunks). But that's somewhat of a luxary feature, so probably shouldn't have highest priority.

    If you make the collider always update itself when a tile changes, it would be nice with some way to add tiles in batch without updating the collider, for when you're procedurally generating large areas at once (although I guess you could just delay adding the TilemapCollider2D component until after you're done).

    Please tell me if you need any more info about my problem. Like I said, it works just fine within Unity, but when exporting the project and running it outside of Unity in Windows, the collider won't regenerate, even if a disable and enable the TilemapCollider2D component through code. Not sure if it's related to the sprite error message or not. The Tilemap itself without the collider seems to generate just fine through code, even in the exported project.
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,266
    You perhaps misunderstand; when you change a tile, it doesn't need to recreate the whole collider, just the shape for that tile (either removing it or adding a new one). The TileMapCollider2D just creates a Box2D shape for each tile and we can update each one separately. Enable/Disable does all of them.

    I've passed on the other problem to the 2D guys involved in the sprite stuff. The problem will lie there and not with the collider which obviously cannot create the shapes without the sprite outline data.
     
    Sir-Spunky likes this.
  5. Sir-Spunky

    Sir-Spunky

    Joined:
    Apr 7, 2013
    Posts:
    132
    Ahh, I see. That sounds nice, then maybe I won't need as much chunk division as I thought once the TileMapCollider2D regenerates correctly.

    Thanks for forwarding it. Hopefully they can see what's wrong. If they can't recreate it I can try to upload the project.
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,266
    When you assign a sprite to a tile, the TileMap can render the sprite. If you also have the tile set to use ColliderType.Sprite then the TileMapCollider2D will be asked to create a collider-shape from that sprite. It'll first check the sprite to see if you've created an explicit sprite outline in the sprite editor for it. You should always try to do this as the fallback is to require the texture is readable and create an outline from that.

    Textures are always readable in the Editor but are not outside of it. To set them readable you need to explicity select that in the Texture Importer however this is far less desirable as it means those textures are kept in memory.

    Use the Sprite Editor to create and tweak sprite outlines and you should be fine.
     
    WoodyDRN likes this.
  7. Sir-Spunky

    Sir-Spunky

    Joined:
    Apr 7, 2013
    Posts:
    132
    Ahh, that explains it! I was a bit unsure how to correctly handle tile collision setting, so I didn't create an outline manually, and noticed it worked anyway in the editor. But now I know. Thanks for the information!
     
    MelvMay likes this.
  8. dougn7

    dougn7

    Joined:
    Nov 5, 2016
    Posts:
    1
    Hi! I'm having the same problem using 2017.2 (update tile on the fly). It's been already fixed?
     
  9. Buswolley

    Buswolley

    Joined:
    Jun 18, 2018
    Posts:
    5
    I’m encountering the same issue here a year later. Procedural tiling is very important for my game; can we please get an update?
     
    miracalious likes this.
  10. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    Instead of setting Read/Write Enabled for your Texture2D, you can set Generate Physics Shape for your Texture2D of your Sprites. This will generate and store a Physics Shape based on the outline of your Sprite which will be used for your Tiles in the TilemapCollider2D in the built player.

    Let us know if that is suitable for you with your usage of procedural tiling!
     
  11. richtaur

    richtaur

    Joined:
    Feb 11, 2015
    Posts:
    1
    Bump: just ran into this same problem. Changing a Tilemap via SetTile() doesn't seem to update its TilemapCollider2D on the fly. The workaround of manually toggling the collider's enabled from false back to true worked for me.
     
  12. kayroice

    kayroice

    Joined:
    Feb 7, 2017
    Posts:
    47
  13. miracalious

    miracalious

    Joined:
    Feb 15, 2015
    Posts:
    2
    Tried all of the solutions mentioned here, none of them work:
    Code (CSharp):
    1. DungeonCollisionmap.RefreshAllTiles();
    2. DungeonCollisionmap.GetComponent<TilemapCollider2D>().enabled = false;
    3. DungeonCollisionmap.GetComponent<TilemapCollider2D>().enabled = true;
    4. DungeonCollisionmap.GetComponent<TilemapCollider2D>().ProcessTilemapChanges();
    5. DungeonGo.SetActive(true); // All manner of toggling the game object has no effect either
    I've got one tilemap that was created in the editor that works, and one tilemap that was created at runtime where collisions don't work.
     
    IndieMarkus likes this.