How to make an image transparent with color.lerp after delay, in a coroutine

So I am trying to do as the title says. I am swapping weapons and the image icons in the UI should have the color become transparent over time after swapping, but then go back to opaque if swapped again. This gives the effect of swapping making the icons show up on the screen and then fading after a couple seconds. This ALMOST is working. However, with my current implementation, since there is a waitForSeconds call made, so there is a delay and the image actually appears on screen, the coroutine lerping still makes the icon invisible without resetting the 5 second delay. I want the behavior that if u swap back and forth over 4 seconds, the color should still not go transparent for another 5 seconds, but currently it goes invisible after 1 with that test case.


Here is my current implementation of the 3 relevant functions:


void SwitchWeaponIcons()
    {
        justSwapped = true;
        Color tempInvis = selectedIconObj.GetComponent<Image>().color;
        tempInvis.a = 1;
        selectedIconObj.GetComponent<Image>().color = tempInvis;

        tempInvis = backbarIconObj.GetComponent<Image>().color;
        tempInvis.a = 1;
        backbarIconObj.GetComponent<Image>().color = tempInvis;

        selectedIconObj.GetComponent<Image>().sprite = weaponIconList[selectedWeapon];
        backbarIconObj.GetComponent<Image>().sprite = weaponIconList[backbarWeapon];
        StartCoroutine(MakeVisible());
    }
    IEnumerator MakeVisible()
    {
        
        Color tempColor1 = selectedIconObj.GetComponent<Image>().color;
        tempColor1.a = 1f;
        selectedIconObj.GetComponent<Image>().color = tempColor1;
        Color tempColor2 = backbarIconObj.GetComponent<Image>().color;
        tempColor2.a = 1f;
        backbarIconObj.GetComponent<Image>().color = tempColor2;



        yield return new WaitForSeconds(5f);
        justSwapped = false;
        StartCoroutine(ColorLerpOut());
    }
    IEnumerator ColorLerpOut()
    {
        Color invisColor = Color.white;
        invisColor.a = 0f;
        for (float t = 0.01f; t < 3f; t+= 0.1f)
        {
            if (justSwapped) break;
            selectedIconObj.GetComponent<Image>().color = Color.Lerp(selectedIconObj.GetComponent<Image>().color,invisColor,t/3);
            backbarIconObj.GetComponent<Image>().color = Color.Lerp(backbarIconObj.GetComponent<Image>().color, invisColor, t / 30);
            yield return null;
        }
        if (justSwapped)
        {
            Color tempColor1 = selectedIconObj.GetComponent<Image>().color;
            tempColor1.a = 1f;
            selectedIconObj.GetComponent<Image>().color = tempColor1;
            Color tempColor2 = backbarIconObj.GetComponent<Image>().color;
            tempColor2.a = 1f;
            selectedIconObj.GetComponent<Image>().color = tempColor2;
            yield return null;
        }
    }

When you call StartCoroutine(MakeVisible()), you can store a reference to that coroutine like this:

public class YourClass
{
    private Coroutine runningCoroutine;
    
    private void Foo()
        {
            runningCoroutine = StartCoroutine(MakeVisible());
        }
[...]

}

That enables you to later do things like StopCoroutine(runningCoroutine).

If you also set runningCoroutine = null at the end of MakeVisible, then you can have other parts of your code effectively check whether MakeVisible is running by checking whether runningCoroutine is null.

Putting it together, you can replace your current line StartCoroutine(MakeVisible()) with this:

if (runningCoroutine != null)
{
    StopCoroutine(runningCoroutine);
}
runningCoroutine = StartCoroutine(MakeVisible());

This basically says, ‘If there’s a five-second timer already running, scrap it, and replace it with this fresh one.’ Hope it helps.

Mhh, did you search on stackoverflow yet? I belive someone allready asked that. but sorry i dont know either…

Figured it out. Rather than worrying about whether the coroutine is still running or not, which is evidently very hard since its not built in, I know there should only be one coroutine of this running at a time and i want to restart it if its running. Luckily, saying stopcoroutine doesnt give you an error if its not running. So here is the finished code block that makes the weapon icons fade after 3 seconds.


    void SwitchWeaponIcons()
    {
        selectedIconObj.GetComponent<Image>().sprite = weaponIconList[selectedWeapon];
        backbarIconObj.GetComponent<Image>().sprite = weaponIconList[backbarWeapon];
        StartCoroutine(MakeVisible());
    }
    IEnumerator MakeVisible()
    {

        Color tempColor1 = selectedIconObj.GetComponent<Image>().color;
        tempColor1.a = 1f;
        selectedIconObj.GetComponent<Image>().color = tempColor1;
        Color tempColor2 = backbarIconObj.GetComponent<Image>().color;
        tempColor2.a = 1f;
        backbarIconObj.GetComponent<Image>().color = tempColor2;

        StopCoroutine("ColorLerpOut");
        StartCoroutine("ColorLerpOut");

        yield return null;
    }
    IEnumerator ColorLerpOut()
    {
        Color invisColor = Color.black;
        invisColor.a = 0f;
        
        yield return new WaitForSeconds(2);
        for (float t = 0.01f; t < 30f; t += Time.deltaTime / 15)
        {
            //if (justSwapped) break;
            selectedIconObj.GetComponent<Image>().color = Color.Lerp(selectedIconObj.GetComponent<Image>().color, invisColor, t / 15);
            backbarIconObj.GetComponent<Image>().color = Color.Lerp(backbarIconObj.GetComponent<Image>().color, invisColor, t / 15);
            yield return null;
        }
    }