Gradually changing Canvas alpha?

This may have been asked a bunch of times in the past, but there are just so many GUI/UI questions out there, and all of them are about something specific (none of which is what I’m looking for).

I have a canvas with 3 Text objects, and I want to gradually fade them all in/out. I added a “Canvas Group” component to the canvas object, and I’m using a script with “Mathf.Lerp” to gradually change its alpha.

    CanvasGroup thisCanvas;

    void Awake () {
        thisCanvas = GameObject.Find("Canvas").GetComponent<CanvasGroup> ();
    }

    void Start () {
        StartCoroutine(Cutscene());
    }

    public IEnumerator Cutscene () {
        thisCanvas.alpha = Mathf.Lerp(0f, 1f, 0.08f);
        yield return new WaitForSeconds (2f);
        thisCanvas.alpha = Mathf.Lerp(1f, 0f, 0.08f);
    }

I’ve been trying lots of different values. All that happens is it either starts the scene with the text slightly visible, then it instantly becomes fully visible and doesn’t disappear afterwards. Or it doesn’t do anything and just sits there, slightly visible.

Right now your code is setting it to .08, waiting 2 seconds, then setting it to .92.

You can use a for loop, increment it by delta time, over a period of 2 seconds, and use ‘x / 2’ as the 3rd parameter for your Lerp.

After the for loop, simply set it to full alpha (because the loop will almost certainly fall just short).

Does that make sense? I can help you with the code if it’s unclear.

You should replace that GameObject.Find with a direct reference. Find is slow. But anyways, on to your question.

There are several post on the forum about fading. My suggestion is to look into a tween engine as they are easier to use. But if you want to use your own, you just need to look at a few examples.

Now, Unity is doing this in an update, but the general idea is the same. You need to have a loop of some sort where you gradually increase the value. Think of it this way, if you start at point A (the first value) and your target is point B (the second value). The third value represents how far along you are between the two points.

In your code, you would be 8% of the way. You need to gradually increase this value till you reach 1f which would be 100%.

Definitely agree about the direct reference. Also, I could mention that you could turn Start() into a coroutine, also. :slight_smile:

Ah ok, I see now. Since it’s not in Update (or in a loop), it’s only running that “Mathf.Lerp” line once. So it’s only increasing, it from 0 to 0.08, then switching it to 1 instantly, and lowering it only by .08.

And yes, I would like help with the code. I don’t know how those variables (deltaTime, amount of seconds, etc.) would fit into a for loop.

Might look something like this:

IEnumerator Start() {
   for(float f = 0; f <= 2; f += Time.deltaTime) {
      thisCanvas.alpha = Mathf.Lerp(0f, 1f, f / 2);       
      yield return null;
   }
thisCanvas.alpha = 1;
}

You could, of course, replace ‘2’ with a variable if you ever plan to change that duration/value.

Hope that helps.

1 Like
CanvasGroup thisCanvas;
    void Awake () {
        thisCanvas = GameObject.Find("Canvas").GetComponent<CanvasGroup> ();
    }
    void Start () {
        StartCoroutine(Cutscene());
    }
    public IEnumerator Cutscene () {
        thisCanvas.alpha = Mathf.Lerp(0f, 1f, 0.08f);//I think you missunderstood how Lerp works.

        yield return new WaitForSeconds (2f); //Waits 2 seconds then goes to the next line, which brings it back to full brightness. So the light variation is never more than 8%.

        thisCanvas.alpha = Mathf.Lerp(1f, 0f, 0.08f); //Again
    }

Lerp is a solid interpolation point between 2 points. It defaults to halfway but you can change it. That is how you use it to smooth, you change the last paramater (the timer) at a fprogrammed rate. rate (most common can get advanced if ya like)

Lerp is this, StartPoint, EndPoint, A value clamped between the start and end point (so basically like a joystick axis). However once you set the axis that is where it is until you move it. It has great usage by just manipulating it to intuitively move between max and min.

So Your coroutine starts. You basically just said thisCanvas.alpha = 0.08f;
Wait 2 seconds.
thisCanvas.alpha = 1f;

A good way to move the t value is to do like
t = 0; //So it will start at off.
Mathf.Lerp(0f,1f,t += 0.08);

t is clamped so even if you overrun it, if you base your light intensity off of t based on (Mathf.Lerp(a,b,t) it can never get higher than b or lower than a.

With that everytime the game loop passes the lerp line it moves further towareds 1.0f at an increment of 0.08f If you use Time.Deltatime as the adder it will add the amount of time since the last fixed update (1 second unless you change it) to t; That makes a nice smooth transition.

So If what you are wanting to do is make the light smoothly fade from off to full on back to full off over and over it might look something like this.

Meh others tried to answer so here ya go. I am a bit out of it so hope I didnt make too many typos, should be close.

public IEnumerator CutsceneAmplify () {
        if(t != 0f){ t = 0;);
        thisCanvas.alpha = Mathf.Lerp(0f, 1f, t +=0.08f);
        if(t < 1f) {
        yield return new WaitForSeconds (2f);
        }
        else {
        yield return StartCoroutine(CutscenDiminish());
        }
    }

public IEnumerator CutsceneDiminish () {
        if(t != 1f){ t = 1f;);
        thisCanvas.alpha = Mathf.Lerp(0f, 1f, t -= 0.08f);
        if(t < 0f) {
        yield return new WaitForSeconds (2f);
        }
        else {
        yield return StartCoroutine(CutscenAmplify());
        }
    }

This code will stay in the first coroutine passing back and forth control with unity until the light is fully on, then it will pass control the the second coroutine which will go back and forth with unity dimming the light. Just make it do a little dance.

Little note, only start coroutines in this manor when you start the first dancer via the void Start() function. Otherwise you will have a mess.

1 Like

Thanks guys for your help. After seeing methos5k’s code, I can see how a for loop could be used. And Xype’s post also helps a great deal, as I did have a slight misunderstanding with how “Lerp” functions.

I got it working now, and I also got it to fade back out at a specific time (in relation to other things done during the cutscene).

Thanks again for all your guys’ help. :slight_smile:

No problem, take it easy :slight_smile:

1 Like

The for loop will work. However it is highly advised against. You want the coroutine to do its calculations really fast and get the control back to the main game loop. Otherwise its kinda redundant to do coroutines. They basically are a loop that runs faster on the side.

Out of curiosity, are you referring to my code (and its loop), or something else?

There may be some misunderstanding here.

The code I wrote only does 1 part of the loop per frame.

Yes Yes again nothing wrong with it. I would rather just drop it. It would work fine. I get into best practices and people get angry, the question is answered I think and I really didnt mean to offend so lets just be friends ok.

No need to fret, I can assure you that I am not angry or offended. :slight_smile:

I was legitimately trying to understand what you were talking about.

I will try to put it simple but I don’t wanna get into it too deep.

Basically If your game loop itself gets a bit of pressure and hiccups a little slowing your coroutine down for a split second no biggy. BUT If your little coroutine is out there with a big or worse hung loop holding up your game getting control back, thats no good.