Search Unity

[SOLVED] How can I change a value smoothly from 1 to 0 over a given number of seconds?

Discussion in 'Scripting' started by xolotlll, Jul 26, 2017.

  1. xolotlll

    xolotlll

    Joined:
    Jul 16, 2017
    Posts:
    18
    Hi all,

    I have a script that fades the screen in and out, but I'd like to make it so that this happens over a precise number of seconds by shifting alpha from 0 to 1 and vice versa as necessary.

    Here's how I call the relevant function from other scripts:
    Code (CSharp):
    1. ScreenFading.ScreenFader.FadeOut(4f);
    4f is where I'd like to put the time the fade should take in seconds.

    Here's the function on ScreenFading:
    Code (CSharp):
    1.         public void FadeOut(float fadeTime)
    2.         {
    3.                 StartCoroutine(DoFadeOut(fadeTime));
    4.         }
    Here's the co-routine on ScreenFading:
    Code (CSharp):
    1.         IEnumerator DoFadeOut(float doFadeTime) //i.e. make screen black
    2.         {
    3.                  while (?????)
    4.                 {
    5.                       ?????
    6.                       yield return null;
    7.                 }
    8.                 yield return null;
    9.         }
    Here's the bit on ScreenFading where it draws the black texture over the screen:
    Code (CSharp):
    1.         void OnGUI()
    2.         {
    3.                 blackAlpha = Mathf.Round(blackAlpha * 100f) / 100f; //round to two places
    4.  
    5.                 GUI.color = new Color(0, 0, 0, blackAlpha);
    6.                 GUI.depth = 0;
    7.                 GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), blackSprite);
    8.                 GUI.color = Color.clear;
    9.         }
    I'd like to make blackAlpha shift from 1 to 0 over doFadeTime seconds (4 in my original example). I'm not even sure how to start though - all I know is that I'd probably use Time.deltaTime. Any suggestions?

    Mathf.SmoothStep also looks promising!

    Thank you.
     
  2. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    Well 0/Number = 0, and Number/Number = 1. So if you want to slowly increment from 0 to 1 over Number seconds, you'd probably want to calculate some currentTime/TotalTime, and then increment currentTime by the Time.deltaTime of the frame.
    Code (csharp):
    1. //inside enumerator
    2. float currentTime = 0;
    3. while (currentTime < totalTime)
    4. {
    5.     var someValueFrom0To1 = currentTime / totalTime;
    6.     currentTime += Time.deltaTime;
    7. }
     
    Deleted User likes this.
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Here's a special variety of for loop which I use for this sort of situation:
    Code (csharp):
    1. public IEnumerator ChangeSomeValue(float oldValue, float newValue, float duration) {
    2. for (float t = 0f; t < duration; t += Time.deltaTime) {
    3. someValue = Mathf.Lerp(oldValue, newValue, t / duration);
    4. yield return null;
    5. }
    6. someValue = newValue;
    7. }
    The "someValue" line is the main one that changes, and you simply assign that to wherever it should be. You can do this with just about any value type that supports lerping.

    PS: Don't use OnGUI (except for like, the most basic of debugging stuff). The new GUI system (based on Canvas) is objectively better.
     
    Con_Games and CakeMuffinCo like this.
  4. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,037
    You can also simplify things a bit with Color.Lerp.
     
  5. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,187
    Personally, I have used tweening engines for many of these things. Does look like you have a couple of good suggestions here as well, but just to toss out other options. LeanTween and Dotween both are available for free and can handle these things very well.
     
  6. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,037
    Those are great options if you want something more than a linear transition, for example a curvy colour transition for health bars as they shrink (50-100% is green, 10-49% is yellow, lower red) - or to fade the screen faster towards the darkest portion of a fadeout.
     
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    You can also use animations for this (which is much easier on the Canvas system than the OnGUI system, as you can literally just animate the color you want to change, no code needed at all except to trigger the animation in the first place.)
     
  8. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    MoveTowards is the best. it is numeric safe for the most part. (you of course still have float inaccuracy there.)

    I would do it simply in the update and let you controll it on the fly.

    Code (csharp):
    1.  
    2. public float target = 0;
    3. public float duration = 1;
    4. private float alpha = 1;
    5.  
    6. void Update(){
    7.     if(duration < 0){
    8.         duration = 0.001f;
    9.     }
    10.     alpha = Mathf.MoveTowards(alpha, target, (1 / duration) * Time.deltaTime);
    11.    
    12.     if(alpha == 0){
    13.         Destroy(gameObject);
    14.     }
    15. }
    16.  
    17. void OnGUI()
    18. {
    19.     GUI.color = new Color(0, 0, 0, alpha);
    20.     GUI.depth = 0;
    21.     GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), blackSprite);
    22.     GUI.color = Color.clear;
    23. }
    24.  
     
    pjkokane21 likes this.
  9. xolotlll

    xolotlll

    Joined:
    Jul 16, 2017
    Posts:
    18
    These are all great suggestions. Thank you!
     
  10. pjkokane21

    pjkokane21

    Joined:
    Mar 18, 2021
    Posts:
    2
    Thanks a lot
    It works