Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Make a sprite flash?

Discussion in '2D' started by Marscaleb, Jan 22, 2014.

  1. Marscaleb

    Marscaleb

    Joined:
    Jan 7, 2014
    Posts:
    973
    I need to be able to make a sprite flash when it gets hit.

    There's actually two things I'm looking for in this regard.
    One is to make the whole sprite flash white, signifying that it took damage. For one frame, regardless of what animation is playing, just have the image displayed as a solid white plus transparency.
    The other is to make a sprite flash invisible for a set amount of time. One frame the sprite will not be rendered, the next it will, the next it won't, repeating until it is told to stop.

    To make the sprite flash white could be done in the animation itself, but that limits things because it will only play on a character that has a special hurting animation. If a character does not, like say a boss that is supposed to get hit repeatedly while it is running around, then that system won't work.

    I can easily write the code that will run each frame to check and change how a sprite is rendered, but I don't know what kind of command can change the visibility of a sprite nor its color, especially without interrupting the animation it is playing.

    I know there is a color attribute on the sprite renderer, but that cannot be modified to turn a sprite white, since the all-white color is the default mode that makes it appear normal; it can't be used to make the sprite brighter than it normally is.
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,398
    Making the sprite flash invisible is simple enough: turn the renderer off and on. Not per frame, however, since framerate varies. You would set it off then on for a particular length of time repeatedly. InvokeRepeating is an easy way to do that.

    --Eric
     
  3. unitylover

    unitylover

    Joined:
    Jul 6, 2013
    Posts:
    346
    I don't know which is less overhead but I've been setting the sprite alpha to 0 and then back to 1 after a delay. Both methods seem to accomplish the flash though! :)
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,398
    The sprite is still being drawn when the alpha is 0, so it's more efficient to disable the renderer, however it would make little difference in this case.

    --Eric
     
  5. Brutang

    Brutang

    Joined:
    Nov 1, 2013
    Posts:
    23
    this will make it blink whatever color 5x if you're looking for somethin else.. maybe just partially translucent. Might be excessive but it works
    Code (csharp):
    1. var whateverColor:Color = Color32(r, g, b, alpha); //edit r,g,b and the alpha values to what you want
    2.     for(var n = 0; n < 5; n++)
    3.     {
    4.         renderer.material.color = Color.white;
    5.         yield WaitForSeconds(.1);
    6.         renderer.material.color = whateverColor;
    7.         yield WaitForSeconds(.1);
    8.     }
    9.     renderer.material.color = Color.white;
    10.  
    Color.white is default of your sprite color.

    Or to disable/re enable it entirely (I havent tested this personally but it should work fine)

    Code (csharp):
    1.  
    2. for(var n = 0; n < 5; n++)
    3. {
    4.      renderer.enabled = true;
    5.      yield WaitForSeconds(.1);
    6.      renderer.enabled = false;
    7.      yield WaitForSeconds(.1);
    8. }
    9. renderer.enabled = true;
    10.  
     
    Last edited: Jan 22, 2014
  6. unitylover

    unitylover

    Joined:
    Jul 6, 2013
    Posts:
    346
    Great example Brutang. I have to do it a bit differently because my player is made up of 7 sprites. Here's how I did it:

    Coroutine
    Code (csharp):
    1.  
    2. /**
    3.      * Coroutine to create a flash effect on all sprite renderers passed in to the function.
    4.      *
    5.      * @param sprites   a sprite renderer array
    6.      * @param numTimes  how many times to flash
    7.      * @param delay     how long in between each flash
    8.      * @param disable   if you want to disable the renderer instead of change alpha
    9.      */
    10.     IEnumerator FlashSprites(SpriteRenderer[] sprites, int numTimes, float delay, bool disable = false) {
    11.         // number of times to loop
    12.         for (int loop = 0; loop < numTimes; loop++) {            
    13.             // cycle through all sprites
    14.             for (int i = 0; i < sprites.Length; i++) {                
    15.                 if (disable) {
    16.                     // for disabling
    17.                     sprites[i].enabled = false;
    18.                 } else {
    19.                     // for changing the alpha
    20.                     sprites[i].color = new Color(sprites[i].color.r, sprites[i].color.g, sprites[i].color.b, 0.5f);
    21.                 }
    22.             }
    23.  
    24.             // delay specified amount
    25.             yield return new WaitForSeconds(delay);
    26.  
    27.             // cycle through all sprites
    28.             for (int i = 0; i < sprites.Length; i++) {
    29.                 if (disable) {
    30.                     // for disabling
    31.                     sprites[i].enabled = true;
    32.                 } else {
    33.                     // for changing the alpha
    34.                     sprites[i].color = new Color(sprites[i].color.r, sprites[i].color.g, sprites[i].color.b, 1);
    35.                 }
    36.             }
    37.  
    38.             // delay specified amount
    39.             yield return new WaitForSeconds(delay);
    40.         }
    41.     }
    42.  
    Usage
    Code (csharp):
    1.  
    2. SpriteRenderer[] sprites = GetComponentsInChildren<SpriteRenderer>();
    3. StartCoroutine(FlashSprites(sprites, 5, 0.05f));
    4.  
    I hope this helps others who also have multiple sprites for their players. Thanks for sharing everyone!
     
  7. Marscaleb

    Marscaleb

    Joined:
    Jan 7, 2014
    Posts:
    973
    Because of the varying framerate, I would elect to switch it every frame. Each rendered frame is when it switches. If i specify a length of time, on slower machines it won't display right. I had that issue when I was working with Unreal; I had an image flash but it wouldn't appear on slow machines because it was called to appear and then disappear before a frame was rendered.

    Also, do you know the syntax for disabling the sprite? What code I would use in a script attached to a game object?

    That's just adjusting the color field that I can see on a sprite in the inspector, isn't it? If that's the case then it can't make the sprite flash white.
     
  8. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,398
    It will look different on different framerates if you do it per-frame, so that's not really a good solution. You can use coroutines like Brutang showed; "yield WaitForSeconds(.1)" will wait approximately .1 second, or at least one frame if the framerate is somehow below 10fps. Different framerates will still give slightly different results because the code is actually still a little framerate-dependent, but at least it will be a lot more consistent than doing it per-frame.

    --Eric
     
  9. Mobaiou

    Mobaiou

    Joined:
    Jun 20, 2014
    Posts:
    13
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class FlashingObject : MonoBehaviour {
    5.  
    6.     /// <summary>
    7.     /// Singleton
    8.     /// </summary>
    9.     public static FlashingObject Instance;
    10.    
    11.     private Color[] colors = {Color.white, Color.yellow};
    12.    
    13.     public void Awake()
    14.     {
    15.         // Register the singleton
    16.         if (Instance != null)
    17.         {
    18.             Debug.LogError("Multiple instances of FlashingObject!");
    19.         }
    20.         Instance = this;
    21.     }
    22.    
    23.     public void MakeObjectFlash(Material material,
    24.                                 float durationTime, float intervalTime)
    25.     {
    26.         StartCoroutine(Flash(material, durationTime, intervalTime));
    27.     }
    28.    
    29.     IEnumerator Flash(Material material, float time, float intervalTime)
    30.     {
    31.        
    32.         Color originalColor = material.color;
    33.        
    34.         float elapsedTime = 0f;
    35.         int index = 0;
    36.         while(elapsedTime < time )
    37.         {
    38.             material.color = colors[index % 2];
    39.            
    40.             elapsedTime += Time.deltaTime;
    41.             index++;
    42.             yield return new WaitForSeconds(intervalTime);
    43.         }
    44.        
    45.         material.color = originalColor;
    46.        
    47.     }
    48.  
    49.     public void MakeObjectFlashSprite(SpriteRenderer sprite,
    50.                                 float durationTime, float intervalTime)
    51.     {
    52.         StartCoroutine(FlashSprite(sprite, durationTime, intervalTime));
    53.     }
    54.    
    55.     IEnumerator FlashSprite(SpriteRenderer sprite, float time, float intervalTime)
    56.     {
    57.        
    58.         Color originalColor = sprite.color;
    59.        
    60.         float elapsedTime = 0f;
    61.         int index = 0;
    62.         while(elapsedTime < time )
    63.         {
    64.             sprite.color = colors[index % 2];
    65.            
    66.             elapsedTime += Time.deltaTime;
    67.             index++;
    68.             yield return new WaitForSeconds(intervalTime);
    69.         }
    70.        
    71.         sprite.color = originalColor;
    72.        
    73.     }
    74.  
    75.     public void MakeObjectFlashSprites(SpriteRenderer[] sprites,
    76.                                        int numTimes, float delay)
    77.     {
    78.         StartCoroutine(FlashSprites(sprites, numTimes, delay));
    79.     }
    80.  
    81.     /**
    82.      * Coroutine to create a flash effect on all sprite renderers passed in to the function.
    83.      *
    84.      * @param sprites   a sprite renderer array
    85.      * @param numTimes  how many times to flash
    86.      * @param delay     how long in between each flash
    87.      * @param disable   if you want to disable the renderer instead of change alpha
    88.      */
    89.     IEnumerator FlashSprites(SpriteRenderer[] sprites, int numTimes, float delay, bool disable = false) {
    90.         // number of times to loop
    91.         for (int loop = 0; loop < numTimes; loop++) {          
    92.             // cycle through all sprites
    93.             for (int i = 0; i < sprites.Length; i++) {              
    94.                 if (disable) {
    95.                     // for disabling
    96.                     sprites[i].enabled = false;
    97.                 } else {
    98.                     // for changing the alpha
    99.                     sprites[i].color = new Color(sprites[i].color.r, sprites[i].color.g, sprites[i].color.b, 0.5f);
    100.                     // Debug.Log(sprites[i].color.r + " " + sprites[i].color.g + " " + sprites[i].color.b);
    101.                     // sprites[i].color = new Color(0, 100, 0, 0.5f);
    102.                 }
    103.             }
    104.            
    105.             // delay specified amount
    106.             yield return new WaitForSeconds(delay);
    107.            
    108.             // cycle through all sprites
    109.             for (int i = 0; i < sprites.Length; i++) {
    110.                 if (disable) {
    111.                     // for disabling
    112.                     sprites[i].enabled = true;
    113.                 } else {
    114.                     // for changing the alpha
    115.                     // Debug.Log(sprites[i].color.r + " " + sprites[i].color.g + " " + sprites[i].color.b);
    116.                     sprites[i].color = new Color(sprites[i].color.r, sprites[i].color.g, sprites[i].color.b, 1);
    117.                     //sprites[i].color = new Color(0, 100, 0, 1);
    118.                 }
    119.             }
    120.            
    121.             // delay specified amount
    122.             yield return new WaitForSeconds(delay);
    123.         }
    124.     }
    125.  
    126.    
    127. }
    128.  
    I've tried what you suggested but can't work with WHITE flash. Why?
     
  10. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Why not just use a custom shader that has a frag like:

    fixed4 t = Tex2D(_MainTexture, i.uv);

    return Lerp(t, fixed4(1, 1, 1, t.a), i.vertColor.r);

    (untested)
    Then on your sprite just move color red from 0 to 1 to turn the sprite to full white. It doesn't break batching nor does it require an extra draw call, and you get your full flash of white simply by changing sprite color.
     
  11. Mobaiou

    Mobaiou

    Joined:
    Jun 20, 2014
    Posts:
    13
    Sorry, can you explain a little bit more. I am interesting in use your tip (mey solution doesn't work very weel)


     
  12. Oshigawa

    Oshigawa

    Joined:
    Jan 26, 2016
    Posts:
    362
    I haven't got the luck to get this working yet :(

    I put the FlashWhenHit and FlashingObject scripts to enemy prefab, but no flashing.
     
  13. gilad905

    gilad905

    Joined:
    May 13, 2017
    Posts:
    2
    I just want to point out that, although I haven't implemented it myself, it might be more appropriate to use an animator for this - after all, this is a kind of animation.
    To make an animator display multiple animations (e.g flashing while still walking) you need another layer (another state machine) to the animator.
    You can then define a new state for flashing, define the transitions into + out of it, and for the animation itself, use any of the properties you guys mentioned in here, e.g SpriteRenderer.Enabled \ SpriteRenderer.Color.
    I'm trying to make this work right now, I will update with the results.
     
  14. Oshigawa

    Oshigawa

    Joined:
    Jan 26, 2016
    Posts:
    362
    @gilad905

    Thanks for the answer, i upgraded the whole flashing thing in my game so i don't need white flashes now, i used colored ones. But it's good to know, though simply replacing the sprite with a white one then bringing back the old one is simple and good enough solution if the sprite is not animated.
     
  15. gilad905

    gilad905

    Joined:
    May 13, 2017
    Posts:
    2
    OK, so I managed to make this work with animation. I think this is also a more dynamic solution, because using animation layers you can easily do stuff like flashing / changing color / other properties, while running other animations on the same object in the same time.
    I will post the method here for anyone looking at this post in the future.

    - Create an animation controller state machine and an animation clip for the flashing state, just like creating a normal animation state.

    * If you want to mix the flashing with another animation (e.g flash while walking), create a new animation layer in the animator and do all below in the new layer. In the new layer's configuration, make sure it's set to Blending: Additive (so it won't override the base layer) and that its weight is set to 1.

    - Enter the animation view (Window -> Animation), chose the wanted GameObject and the empty animation clip you just created. If any properties are already attached to the clip, remove them.

    - Click 'Add Property' -> Sprite Renderer -> Enabled -> the '+' icon near it. Using this, you make the object flash by turning SpriteRenderer.Enabled on and off. But for a different effect than flashing, you can use any other property here.

    - In the 'Samples' box, write 2 (you only need two samples). The timeline should have a key at 0:0 and another key at 1:0. Insert a new key at 0:1. Make sure that at 0:0 SprireRenderer.Enabled is checked, and on 0:1 it is unchecked.

    The GameObject should now flash when this state is activated by the animator.
     
    dimaveschikov and colinbrandt like this.
  16. Oshigawa

    Oshigawa

    Joined:
    Jan 26, 2016
    Posts:
    362
  17. colinbrandt

    colinbrandt

    Joined:
    Feb 6, 2017
    Posts:
    1
    gilad, thanks for your explanation! I was able to get my sprite to blink on and off by enabling/disabling the sprite renderer, but I'm having a hard time figuring out how to get it to flash white. The issue is I can't change the sprite renderer color to white, because it's already set to white (so that the sprite image retains its image color values). I thought maybe I could switch between a white sprite and back to my normal sprite of a guy running, but the white sprite takes over and just blinks between a white box and nothing.

    Any ideas?
     
  18. Oshigawa

    Oshigawa

    Joined:
    Jan 26, 2016
    Posts:
    362
    Just make a white colored sprite and swap it for a moment. Unfortunately, animations complicate things a bit.
     
  19. BarthaSzabolcs

    BarthaSzabolcs

    Joined:
    Apr 9, 2019
    Posts:
    8
    If you swap the default sprite material with a GUI/TextShader material, then swap it back you got the desired effect.
    It will work with animations too.

    I made a quick tutorial about this, if you need some more explanation:


    Also you can find a GitHub linked in the description.
     
    hms0589 likes this.
  20. bwaite87

    bwaite87

    Joined:
    Nov 23, 2017
    Posts:
    17
    If you want a more modern answer using URP/Shadergraph, I've made a simple tutorial to showcase how this can be done: