I'm trying to use Unity's 2017 tilemap features. What I would like to do is push a tile's sprite up (change its offset), so that the sprite moves up pixel by pixel and the top of the sprite loops (wraps) back around to the bottom. Basically, I want to animate my "Water" sprite without having to build 20 different versions of the sprite to achieve the same effect. I was able to do this in Rotorz tiles by accessing its Atlas' MainTexture Offset or something like that but this product is discontinued. This animation is similar to the water in classic RPG games like Ultima 4.

More than that, I would just love to have runtime access to the tiles to do other things: change out the entire sprite on a single tile, change the color, etc.

I have made a custom Tile class using this example: https://docs.unity3d.com/Manual/Tilemap-ScriptableTiles-Example.html

But this only seems to affect tiles at the time of placement.

Is this possible and does anyone have a good example? Docs on this feature are scarce.

  • If I'm not mistaken tiles can have runtime logic (Ruletile for example) and brushes are resposible for placing/modifying tiles. If you haven't already you can download 2d additions like the mentioned Ruletile from Unity's Github (2d-extras and few others). – Nikaas Apr 16 at 10:10
  • Ruletile is an example in the 2d editions, which inherits from the Tile class, but all its callbacks fire only when the tile is placed. Not at runtime. Unless you're talking about an entirely different class from Tile/TileBase. – fregas Apr 16 at 12:22
  • I'm not familiar with tilemap, but I managed to do exactly the same thing (for water) for a past game of mine, using a simple texture on an object and changing it's offset through code. Would that interest you? – TomTsagk Apr 18 at 12:59
  • Thanks @TomTsagk. I do know how to do that on a gameobject. It's the tile system that makes it difficult. Unless you know a way to build this onto a sprite sans a game object. – fregas Apr 18 at 22:25
  • Hey, what does this dude have against multiple sprites to do the same thing? Can't he just make one tile with a map? AKA 200 x 10 image? – FreezePhoenix Apr 20 at 16:50

Have a look at the Unity Examples on their GitHub.

Pay special attention to the Animated Tile Example:

[Serializable]
public class AnimatedTile : TileBase
{
    public Sprite[] m_AnimatedSprites;
    public float m_MinSpeed = 1f;
    public float m_MaxSpeed = 1f;
    public float m_AnimationStartTime;
    public Tile.ColliderType m_TileColliderType;

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

    public override bool GetTileAnimationData(Vector3Int location, ITilemap tileMap, ref TileAnimationData tileAnimationData)
    {
        if (m_AnimatedSprites.Length > 0)
        {
            tileAnimationData.animatedSprites = m_AnimatedSprites;
            tileAnimationData.animationSpeed = Random.Range(m_MinSpeed, m_MaxSpeed);
            tileAnimationData.animationStartTime = m_AnimationStartTime;
            return true;
        }
        return false;
    }
}

One thing to note is because of the definition of the framework, you can't get away from an array of sprites for a tile. You can create them dynamically from an asset but that's too complicated to go into on this question.

You can modify tiles at runtime by overriding the RefreshTile and GetTileData methods.

public override void RefreshTile(Vector3Int location, ITilemap tileMap)
{
    // refreshes self and neighbors
    for (int yd = -1; yd <= 1; yd++)
        for (int xd = -1; xd <= 1; xd++)
        {
            Vector3Int position = new Vector3Int(location.x + xd, location.y + yd, location.z);
            if (TileValue(tileMap, position))
                tileMap.RefreshTile(position);
        }
}

public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
{
    MyCustomUpdate(location, tileMap, ref tileData);
}

I agree, information is scarce at the moment, because it's such a new feature. These examples are just about the best leg up I've been able to find.

As you solve your problem, come back and post an answer to your question with the solution you came up with to help others. Now is a prime time to earn some extra reputation :)

  • I tried this very example, and I can use the brute force way of animating tiles by swapping them out. However, I still can't seem to get runtime access to any of the tile properties. GetTileData and RefreshTile do not seem to get fired at runtime. Just at design/placement time. – fregas Apr 18 at 14:17
  • You'd have to double check, but I think GetTileData will be called every frame if the tile is flagged as animated. I'm wanting to say that when it's not animated, it's only called once to improve performance. – Stephan Apr 18 at 14:45
  • it does not. I have an example animating and these method so not get called. The best I've seen is to call RefreshTile manually. Even still, you can't change the offset of the sprite. You swap it out though. – fregas Apr 22 at 15:46

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.