Objects not fading out the way they should

Hi, I’m still pretty new to unity and I am having a bit of an issue. I’m trying to get a list of objects to fade out by setting the alpha value in their TextMeshPro component’s color to 0 by doing a loop to lower the value of it by 0.01 every loop. This is what I have:

foreach (var btn in _titlebuttons) // iterate through the objects
{
    var tmp = btn.transform.GetChild(0).GetComponent<TextMeshPro>(); // get the textmeshpro components
    var a = tmp.color.a; // get the current alpha value
    if (a > 0) // check if alpha is bigger than 0
    {
        a -= 0.01f; // subtract 0.01 from alpha
        tmp.color = new Color32(1, 1, 1, (byte)a); // set the new color value
        Debug.Log(a); // log output of a
}

This code is in a function that checks what game the state is in and manages code for when in that state, and that function is called every frame.
(looks like this):

private void Update()
{
    StateLogic();
}
private void StateLogic()
{
    switch(currentState)
    {
        [...]
    }
}

The way I imagine this working is once the state is changed, the title screen buttons fade out and that’s that, however in the game they just disappear immediately and the console outputs 0.99 4 times before stopping.

I know I could just use a canvas group to do the same thing but I find the unity GUI system a hassle to work with, and some effects I want to do like simply moving an on screen spinning cursor to the button being hovered over doesn’t work because I can’t get the name of the object I’m hovering over no matter how hard I try, so I’m trying to just instantiate everything inside of code.
I’d really appreciate either an easier way to do menu GUI or help solving this issue because I’ve been trying to get the menus working for weeks to no avail.

The gui isn’t that hard to work with, especially compared to the old days. :slight_smile:
The issue is you’re using a foreach loop and from what I can see, possibly not within a coroutine, since you don’t have any yields in there.

If you don’t have a yield inside a loop, the loop is going to run until complete. It will never yield to allow any visual updates. Which means it enters the loop, does it’s thing until the loop ends, exits the loop before it allows any visual changes, which from the viewers point of view is not a gradual fade.

You can do exactly what I said and add a yield, but I suggest a tweening engine such as LeanTween or DoTween. Both are free on the asset store and learning one will help you so much when dealing with stuff like fades, gui animation, etc.

As for the other issue. Implementing OnMouseOver or OnPointerEnter, should help make those sorts of thing much easier.

Everything that Brath says above (100% of code executes instantly unless you are in a coroutine), plus this:

Fading, simple and easy:

Issue with OnMouseOver/OnPointerEnter is I need the object’s name in order to reference the object later in the code to move the visual cursor next to it. Every time I attempted to do that I got null. I’ll try putting it in a coroutine and adding a yield though and see if that works.

Also my issue with seeing the GUI as a hassle in the editor is the fact that things are reliant on said object not only being in the editor but also enabled. When I was trying to make the transition from the title screen to the game setup screen for example it’d fail due to the canvas not being enabled when I tried to enable it. Issues like that is why I decided to make everything instantiate inside the code, so I’d always have a reference to the object even if its disabled in the scene.

In that case this has NOTHING to do with fading or Unity.

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Steps to success:

  • Identify what is null
  • Identify why it is null
  • Fix that

I tried everything I could think of but couldn’t fix it. Anyways that was another issue entirely that lead to me instantiating everything in code, not the problem I’m looking to solve here.

I tried making the fade into a coroutine that looks like this:

[...]
foreach (var btn in _titlebuttons)
{
    var tmp = btn.transform.GetChild(0).GetComponent<TextMeshPro>();
    StartCourotine(FadeText(tmp, tmp.color.a, false));
}
[...]
private static IEnumerator FadeText(TextMeshPro obj, float a, bool up) // get object, get whether it should fade in or out
{
    // fade in
    if (up)
    {
        if (a < 1)
        {
            a += 0.01f;
            obj.color = new Color32(1, 1, 1, (byte)a);
            Debug.Log(a); // log
        }
    }
    else
    {
        if (a > 0)
        {
            a -= 0.01f;
            obj.color = new Color32(1, 1, 1, (byte)a);
            Debug.Log(a); // log
        }
    }
    yield return null; // no idea if this is why it is not working
}

I’m probably doing this wrong but its still disappearing instantly and I’m still seeing 0.99 in the console a couple of times before it stops.

If you re-read the three steps, none of them involve “thinking of everything.”

Start with step #1: Identify what is null.

Nobody here can do that for you. Only YOU can do it.

Coroutines are NOT suitable for fading and my first reply to you explains why, and how to do it without coroutines.

Since you didn’t read that post, I’ll offer it again for you here:

Fading, simple and easy:

https://discussions.unity.com/t/808656/5

You’re welcome to keep trying combinations, and when you have exhausted all the mis-implementations of coroutines (which aren’t even suitable in the first place) and finished “thinking of everything,” the actual steps you need to fix your actual problem are awaiting you in this post.

Oh that’s… actually really simple. But wasn’t the point of the coroutine to get it to fade while in a foreach loop? Do I need to find a way to somehow fade each one without a foreach loop?

I have this now:

private static void FadeText(TextMeshPro obj, float a, bool up)
{
    float end;
    if (up)
        end = 1;
    else
        end = 0;
    obj.color = new Color32(1,1,1,(byte)Mathf.MoveTowards(a, end, 2.0f * Time.deltaTime));
}

but its still disappearing instantly due to that foreach loop, but I don’t know any other way to fade out all the objects other than manually referencing every single one which seems tedious and inefficient
Also I apologize if I seem a bit dense, I’m trying my best to understand here.

Great, set that aside gently, go back to my post and implement the basic three parts:

  • currentValue
  • desiredValue
  • an Update() function to move them together every frame.

Seriously. Just get that working FIRST.

NOW: use Debug.Log() to PROVE that the value smoothly goes from 0 to 1 and back to 0, and test for debug keypresses (such as A, B) to trigger desired to 0 and 1.

Until that works, don’t even CONSIDER your buttons. Just put them out of your mind.

Once you have actually implemented the three parts above, only then can you now route the current value over to where you need it.

Okay so I instantiated a test object that has a TextMeshPro component, and set it to where pressing A would try to fade it in with the FadeText function, and D would fade it out.
Despite this not being in a foreach loop, the text disappears instantly as well, and attempting to fade it back in with A fails. It would also seem that pressing A before pressing D also makes it disappear. Not sure what is causing this.
The way I’m trying to do current and desired is by just using the current alpha value (obj.color.a) and the desired value being set by whether the function is called with a true or false parameter. (true = desired value is 1, false = desired value is 0, A calls it with true, D calls it with false.)
Pressing A does increase the value to 1, although it happens instantly and again for some reason does not make the object reappear…

I’ve been stuck on this for the past hour, I can’t seem to get the fade in/out to work at all for anything. I keep rewriting how I’m setting the initial current value, how its checking for what to set it to, how it actually sets the value to the desired value, no matter what I try the console output either is complete random numbers that aren’t even close to what they should be, 0.99, 0.01, and never does it just smoothly transition to the number. I don’t get what I’m doing wrong here.

private void Update()
{
    if (Input.GetKeyDown(KeyCode.A))
    {
        FadeTest(1, false);
    }
    else if (Input.GetKeyDown(KeyCode.D))
    {
        FadeTest(0, true)
    }
}

private void FadeTest(float currentValue, bool up)
{
    float desiredValue;
    if(up)
    {
        desiredValue = 1;
    }
    else
    {
        desiredValue = 0;
    }
    currentValue = Mathf.MoveTowards(currentValue, desiredValue, 2.0f * Time.deltaTime);
    Debug.Log(currentValue);
}

I genuinely don’t understand why this isn’t working. I’m just… so confused.

You’re only calling FadeTest once, when the key is down, so MoveTowards is also only going to fire once as well. You need to move logic that you want to execute every frame to an appropriate place, like Update.

1 Like

I’m telling you, follow what the other post said.

This means line 24 must be in an Update() function.

void Update()
{
  currentValue = Mathf.MoveTowards(currentValue, desiredValue, 2.0f * Time.deltaTime);
}

That must be run every frame, as it states in the link above.

Now add your debugging, which you started above, which will change your Update into:

void Update()
{
    // debugging keys
    if (Input.GetKeyDown(KeyCode.A))
    {
        desiredValue = 1;
    }
    else if (Input.GetKeyDown(KeyCode.D))
    {
        desiredValue = 0;
    }

    // (as originally done)
    currentValue = Mathf.MoveTowards(currentValue, desiredValue, 2.0f * Time.deltaTime);

    // debugging output
    Debug.Log(currentValue);
}

When the above works 100%, then use currentValue to do whatever you want fade-wise.

I managed to sort of get it working but i think i’m just going to attempt to get it working with unity’s gui system again rather than instantiating everything via code.