Unity-Technologies / 2d-extras

Fun 2D Stuff that we'd like to share!
Other
1.54k stars 342 forks source link

tilemap collisions not working on animated tiles #130

Open SherbertLemon64 opened 4 years ago

SherbertLemon64 commented 4 years ago

it may just be me as I am quite new.

In my tilemap, I have some animated, some not and only the unanimated tiles have colliders when a collider is applied. look for the lava which is not animated, it also has a collider (yes all the lava is in the lava tilemap)

image

ChuanXin-Unity commented 4 years ago

Currently, not all the Sprites in the animation of the AnimationTile do not contribute to the collider shape for the TilemapCollider2D. Only the initial Sprite will contribute to the collider shape for the TilemapCollider2D.

I can't really tell from the image, but did you want each animated Sprite in the AnimationTile to update the collider shape when the animation changes the Sprite?

SherbertLemon64 commented 4 years ago

Thanks for the response.

Sorry for the unclear image. In this game, i wanted it to restart if you fell into the lava, however the none of the animated lavas would contribute to the collier.This was fine for this project as I made it if not on the bricks, however for the project I am working on now that will not be possible. Are you planning to fix the collides any time soon? I will do a workaround at the moment however it would be nice to have this at some point.

ChuanXin-Unity commented 4 years ago

image

If you set the collider type of the Animated Tile to Sprite, you should be able to create a collider shape in the TilemapCollider2D for your lava tile.

image

For example, I have set the collider shape for my animated Waterfall tile here and it has generated collider shapes for these tiles. You can see the collider shape based on the green outlines around it.

Are you unable to generate these shapes for the Lava tile?

wmolter commented 4 years ago

I have (what seems to be) a related issue.

EDIT: I also tried this with the animated tiles from this package. I have the same issue using those AnimatedTiles.

Anyway, I'm trying to get a custom animated tile to have a collider - it doesn't need to change with the animation, just needs to be there all the time. In my game, I'm switching between a few different TileMaps fairly frequently (different "planes" of existence), so they're all in memory, and I just activate and deactivate the GameObjects for them when traveling between. The tilemaps are procedurally generated as you explore them.

Strangely, upon exploring tiles for the first time the collision works perfectly. However, after leaving that plane and re-entering (meaning the tilemap, its gameobject, collider, etc. were deactivated and reactivated) the collision for the animated tile type no longer works for the tiles explored previously. (Newly explored tiles of the animated type still have collision.) I've tried using both "Grid" type and "Sprite" type for the ColliderType in the tile - same result.

A brief investigation confirms that the animation has something to do with it - returning false from GetTileAnimationData fixes the collision, but of course it no longer animates. I couldn't find any more information about how the animation or tile data is used, and it didn't look like I could subclass TileMap and change some functionality there - I don't think the methods are exposed. Of course, I'm not too experienced with 2D in Unity and TileMaps so it's likely I'm missing something easy.

Tile code (again, I copied from the docs and added two lines to try to make collision work.)

public class AnimatedTile : TileBase {
    public Sprite[] m_AnimatedSprites;
    public Tile.ColliderType colliderType;
    public float m_AnimationSpeed = 1f;
    public float m_AnimationStartTime;

    public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData) {
        tileData.colliderType = colliderType;
        if(m_AnimatedSprites != null && m_AnimatedSprites.Length > 0) {
            tileData.sprite = m_AnimatedSprites[m_AnimatedSprites.Length - 1];
        }
    }

    public override bool GetTileAnimationData(Vector3Int location, ITilemap tileMap, ref TileAnimationData tileAnimationData) {

        if(m_AnimatedSprites != null && m_AnimatedSprites.Length > 0) {
            tileAnimationData.animatedSprites = m_AnimatedSprites;
            tileAnimationData.animationSpeed = m_AnimationSpeed;
            tileAnimationData.animationStartTime = m_AnimationStartTime;
            return true;
        }
        return false;
    }
}

Generation code (runs every frame when the plane is enabled)

void UpdateTiles() {
        Vector3 playerPos = player.transform.position;
        Vector3Int playerTile = player.CurrentTile;
        int chunkSize = Mathf.CeilToInt(2*player.LOS)+1;
        for(int i = -1; i < chunkSize; i++) {
            for(int j = -1; j < chunkSize; j++) {
                Vector3Int position = playerTile + new Vector3Int(i - chunkSize/2, j - chunkSize/2, 0);
                if(map.GetTile(position) == null && (position - playerPos + new Vector3(.5f, .5f, 0)).magnitude < player.LOS) {
                    int index = TileIndex(position);
                    map.SetTile(position, allTerrainData[index].tile);
                }
            }
        }
    }

(double edit note: I'm an idiot for not realizing right away from where you were getting the AnimatedTile class....)

ChuanXin-Unity commented 4 years ago

However, after leaving that plane and re-entering (meaning the tilemap, its gameobject, collider, etc. were deactivated and reactivated) the collision for the animated tile type no longer works for the tiles explored previously. (Newly explored tiles of the animated type still have collision.) I've tried using both "Grid" type and "Sprite" type for the ColliderType in the tile - same result.

Would you elaborate more about how you are deactivating and reactivating the Tilemap? This would help a lot in identifying the issue.

Also, which version of Unity are you using?

wmolter commented 4 years ago

I'm using Unity 2019.3.0f6 (Personal).

I call SetActive(false) and SetActive(true) on the parent of the Tilemap object to deactivate and reactivate it.

//planes is a list that contains the parents of the tilemap objects
void ActivateInternal(int destinationLevel) {
        for(int i = 0; i < planes.Count; i++) {
            if(i == destinationLevel)
                continue;
            planes[i].gameObject.SetActive(false);
        }
        planes[destinationLevel].gameObject.SetActive(true);
        activePlane = destinationLevel;
    }

The actual objects look like below. If it matters, the script with the above ActivateInternal method is in the "Manager" object (top of the hierarchy). Like I said, the tilemaps are disabled and enabled by SetActive on the its parent, here the "Terrestrial" and "CavernLayer" objects. hierarchy_setup grid_setup

tilemap_setup

ChuanXin-Unity commented 4 years ago

Hi, sorry for the late reply. I checked this out and this is a bug with the Unity Editor and will be fixed in a future version.

I will update here with the version of the Unity Editor that has this fixed!

wmolter commented 4 years ago

Thanks for letting me know that it is confirmed a bug!

apkatsikas commented 3 years ago

any updates on this?

ChuanXin-Unity commented 3 years ago

@apkatsikas This has been fixed a while back and is available back to Unity 2019.4 I believe.

apkatsikas commented 3 years ago

cool - i will try. my issue was de-parenting and then parenting an animated tile seemed to erase the collider data. hopefully this will fix for me

apkatsikas commented 3 years ago

worked in 2019.4.10f1 - thanks @ChuanXin-Unity