0
\$\begingroup\$

I would like to make it so if the cursor enter a tile, it becomes "higlighted" (slightly whitened), like the left tile below.

A highlighted object, and a base one

I'm quite new to Unity, and after reading an article from Thomas Mountainborn (http://thomasmountainborn.com/2016/05/25/materialpropertyblocks/) I managed to do this with a simple shader on an Object, and changing a parameter in a MaterialPropertyBlock when the mouse enter or quit its collider.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Highlight: MonoBehaviour
{
    [SerializeField]
    private float baseHighlightFactor;

    private Renderer _renderer;
    private MaterialPropertyBlock _propBlock;
    private float _highlight;

    void Awake()
    {
        _propBlock = new MaterialPropertyBlock();
        _renderer = GetComponent<Renderer>();
        _highlight = 0;
    }

    private void Update()
    {
        // Get the current value of the material properties in the renderer.
        _renderer.GetPropertyBlock(_propBlock);
        // Assign our new value.
        _propBlock.SetFloat("_hooverFactor", _highlight);
        // Apply the edited values to the renderer.
        _renderer.SetPropertyBlock(_propBlock);
    }

    private void OnMouseEnter()
    {
        _highlight = baseHighlightFactor;
    }

    private void OnMouseExit()
    {
        _highlight = 0;
    }
}

I wondered if I could do the same with tiles, but with scriptable tiles I can't seem to do it, since the Renderer is a component of the Tilemap and not the Tile itself.

Am I going the wrong direction? I would not like to duplicate each sprite (highlighted/not highlighted) since I have a lot of them. I guess I could use Objects instead of Tiles, but Tilemap properties could be useful for other parts of my project.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ It sounds like what you really want to ask is "how to highlight a tile in a TileMap". Using MaterialPropertyBlock was a guess at an answer, and one that - as you've found - does not work, so ask about the root problem you want to solve, not the guessed-at solution. \$\endgroup\$
    – DMGregory
    May 8 at 19:22

1 Answer 1

1
\$\begingroup\$

Although tilemap is a whole, it can get the corresponding sprite through the mapping of world coordinates and grid coordinates.

enter image description here

Code:

using UnityEngine;
using UnityEngine.Tilemaps;

public class NewBehaviourScript : MonoBehaviour
{
    public GridLayout gridLayout;
    public Tilemap tilemap;
    private Vector3Int pLast;
    void Start()
    {
    }
    void Update()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);
        if (hit.collider != null)
        {
            Vector3Int p = gridLayout.WorldToCell(hit.point);
            if (p == pLast)
            {
                return;
            }
            if (tilemap.HasTile(p))
            {
                tilemap.SetTileFlags(p, TileFlags.None);
                tilemap.SetColor(p, Color.green);
                if (tilemap.HasTile(pLast))
                {
                    tilemap.SetColor(pLast, Color.white);
                }
                pLast = p;
            }
        }
    }
}

As for MaterialPropertyBlock, Basically it's a performance optimized way. It saves memory by having multiple spriteRenderers share a common material instance. In tilemap, This is already handled internally, you don't need to worry about it.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .