Runtime Access to Unity 2d Tiles

Runtime Access to Unity 2d Tiles

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.  

Solutions/Answers:

Answer 1:

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 🙂

References