Koma
Koma

Reputation: 153

Can i use IEnumerator as Update func?

I have some structs like object - 4 child object - in each child 2 more child. I want for each child object change alpha of their color.

I created IEnumarator that should change alpha but when i test this it only changes for 0.8, not to 0, and i also want to change it by time, smoothly for 2 seconds for example, but it happens quick

imageComponents = gameObject.GetComponentsInChildren<Image>();
textComponents = gameObject.GetComponentsInChildren<Text>();    

IEnumerator HideAllBoosters(Transform _object)
    {
        foreach (Image image in imageComponents)
        {
            Color _color = image.GetComponent<Image>().color;
            _color = new Color(_color.r, _color.g, _color.b, 0);
            image.GetComponent<Image>().color = Color.Lerp(image.color, _color, 10 * Time.deltaTime);
        }
        foreach (Text text in textComponents)
        {
            Color _color = text.GetComponent<Text>().color;
            _color = new Color(_color.r, _color.g, _color.b, 0);
            text.GetComponent<Text>().color = Color.Lerp(text.color, _color, 10 * Time.deltaTime);
        }
        yield return null;
    } 

Idk how to do that right, mb i should change color in Update for each object but i dont sure its good for clear and easy code, so what im asking for - can i use another IEnumerator for each object which would work like an Update, smth like:

    foreach (Image image in imageComponents)
    {
         StartCourutine(changeAlpha(image));
    }

Upvotes: 0

Views: 612

Answers (1)

Remy
Remy

Reputation: 5173

The error is in passing 10 * Time.deltaTime as the t value for Lerp(Vector3 a, Vector3 b, float t);

If you look at the documentation for Lerp():

When t = 0 returns a. When t = 1 returns b. When t = 0.5 returns the point midway between a and b.

This means that in order for your alpha to have a nice fade, the t value of Lerp() should be a value that goes from 1 to 0 (or 0 to 1 if you want to fade in) over a certain time. Right now you are passing in 10 * Time.deltaTime this will always be the same value, based on the framerate. (in this case that would be about 0.8).

To fix this issue you need t to be a value that slowly increases/decreases (depending on wether you want to fade in or out) between 0 and 1 . One way of doing this is by encasing your logic in a while loop.

float speed = 0.01f; 
float time = 0;
while ( time < 1)
{
    time += speed;
    //Rest of code
}

This will increment the time value by speed(in this case 0.01) every time the loop runs, which in this case is for 100 iterations (0.01 * 100 = 1).

We can now apply this time value as the t value in the Lerp() method to make it a smooth transition

image.color = Color.Lerp(image.color, _color, time);

If you want your fade to take more or less time, simply increase or decrease the value in speed.

the total implementation would look something like this (notice that I've also done some optimizations that I will cover later)

public float speed = 0.01f; //The speed at which the fade happens

private Image[] imageComponents;
private Text[] textComponents;

void Start()
{
    imageComponents = gameObject.GetComponentsInChildren<Image>(); //Cache the images so we don't have to find them every time
    textComponents = gameObject.GetComponentsInChildren<Text>(); //Cache the texts

    StartCoroutine(HideAllBoosters());//Start the Coroutine
}

IEnumerator HideAllBoosters()
{
    float t = 0; //Start value for our loop
    while (t < 1) // 1 indicates the max value of t at which the loop stops. In this case after 100 iterations since the speed is 0.01
    {
        t += speed;

        foreach (Image image in imageComponents)
        {
            Color _color = image.color;
            _color = new Color(_color.r, _color.g, _color.b, 0);
            image.color = Color.Lerp(image.color, _color, t); //t dictates how far in the interpolation we are.
        }
        foreach (Text text in textComponents)
        {
            Color _color = text.color;
            _color = new Color(_color.r, _color.g, _color.b, 0);
            text.color = Color.Lerp(text.color, _color, t);
        }
        yield return null;
    }
}

The optimizations I've done: The arrays you loop through imageComponents and textComponents are already of type Image and Text. This means that when you loop through them in a foreach() loop Image image and Text text are already of their respective types, and will already hold a reference to their component. What this means is that your .GetComponent<Image>() and .GetComponent<Text>() calls are unnecessary.

In example:

Color _color = image.GetComponent<Image>().color;

is the same as

Color _color = image.color;

I have also removed the Transform _object parameter that HideAllBoosters required, as this didn't seem to be used in the method at all. It may be that you do use this value somewhere later in the function that is outside the scope of this question. If that is the case you need to include it ofcourse.

Upvotes: 1

Related Questions