Search code examples
unity-game-enginesprite

Unity 2D - Showing health on the sprite as red when the health is dropping


I am trying to make the enemy/player become red temporarily after taking damage. I was thinking as one of them takes damage, a red effect moves up on either player/enemy to show how much health is left. How could I do this?

enter image description here

enter image description here

So I think I may have found a way with a sprite mask?

Sprite 1 - Sprite of the desired sprite, and it doesn't interact with a sprite map Sprite 2 - I make a new sprite with a modified version of sprite one to be red that is visible within a sprite mask Sprite Mask - I create a sprite mask with a rectangle shape

Then I somehow translate the position and scale of the sprite mask into a range that the health can interact with and then the mask will change the y of the scale and position as health is taken

So now I'm stuck on finding a way to take the pos and scale and convert it into some way that it interacts with the health correctly

For some reason the animation still plays with the other sprite being shown and idk why but it works

    IEnumerator TakeDamageCorountine(int damage){
    currentHealth = currentHealth - damage;
    float maskPosY = 3.25f/currentHealth;
    float maskScaleY = 6.9f/currentHealth;
    if(gameObject.activeInHierarchy == true){
        spriteMask.localPosition = new Vector3(0.051f, maskPosY, 0f);
        spriteMask.localScale = new Vector3(8.884337f, maskScaleY, 1);
        print("Position: " + spriteMask.position + "Scale: " + spriteMask.localScale);
    }
    yield return new WaitForSeconds(.75f);
}

enter image description here


Solution

  • I think what you can do is indeed go for a SpriteMask and have an underlying second SpriteRenderer for the tint.

    In order to simplify the calculations I would use the following

    • Your original sprite
    • Note down
      • the pixel size (in particular height!) of the texture
      • the import settings -> Pixels Per Unit
    • Create a new texture (e.g. paint) with the same pixel dimensions and completely white
    • Your original SpriteRenderer
      • without any color tint at all!

      • Then add children to it with the following hierarchy and settings

        YourMainSpriteRenderer
        |-- MaskAnchor
            |-- MaskVisuals
        

        where

        • YourMainSpriteRenderer:

          • SpriteRenderer: no color tint (fully white)
          • SpriteMask: use same sprite as mask and adjust cutoff etc

          enter image description here

        • MaskAnchor:

          • Transform: Y = -pixelSize / 2 / Pixels Per Unit (values from second step above)

            in my example the texture is pixels height is 395, pixels per unit is default at 100 -> 395 / 2 / 100 = 1.93

          enter image description here

        • MaskVisuals :

          • Transform: Y = pixelSize / 2 / Pixels Per Unit (same as above but positive)

          • SpriteRenderer: the fully blank texture, your desired color overlay (e.g. red and alpha < 1), Mask InteractionVisible Inside Mask, Order in Layer -> 1 (or at least higher then the parent)

          enter image description here

    Now you should see your original sprite overlaid by the color but only within its mask.

    And thanks to the added MaskAnchor all you need to do to adjust its amount of fill from 0 to 1 is setting the MaskAnchor.transform.localScale.y to a value of 0 to 1.

    enter image description here

    This you can easily do by script now (assuming e.g. the color tint shows the health and shrinks over time)

    maskAnchor.localScale = new Vector3(1, currentHealth / maxHealth, 1);
    

    otherwise simply invert to make the fill grow while the enemy looses health

    maskAnchor.localScale = new Vector3(1, 1 - currentHealth / maxHealth, 1);