Using a Coroutine in Unity3D to fade a game object out, and back in. Looping infinitely

Viewed 4197

I'm trying to get a game object in Unity 3D to fade out(fade speed should be adjustable from editor), pause/wait 2 seconds (pause length be adjustable from editor), and fade back in, looping infinitely. Coroutine is what I'm trying to utilize here to decrease alpha value but I'm unsure of exactly where I'm making my errors.

I'm getting a single error. (Cannot convert method group "FadeOut" to non-delegate type "object")

Here is my code:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScriptFader : MonoBehaviour
{
    // attached game object for fading
    public GameObject Sphere;

    // fade speed length
    public float fadeSpeed;

    //Pause length between fades
    public int fadePause;

    void Awake()
    {
        StartCoroutine(FadeOut(fadeSpeed));
    }


    //Fade Out Coroutine
    public IEnumerator FadeOut(float fadeSpeed)
    {
        Renderer rend = Sphere.transform.GetComponent<Renderer>();
        Color matColor = rend.material.color;
        float alphaValue = rend.material.color.a;


        //while loop to deincrement Alpha value until object is invisible
        while (rend.material.color.a > 0f)
        {
            alphaValue -= Time.deltaTime / fadeSpeed;
            rend.material.color = new Color(matColor.r, matColor.g, matColor.b, alphaValue);
            yield return new WaitForSeconds(fadePause);
        }
        rend.material.color = new Color(matColor.r, matColor.g, matColor.b, 0f);
        StartCoroutine(FadeIn(fadeSpeed));
    }

    //Fade In Coroutine
    public IEnumerator FadeIn(float fadeSpeed)
    {
        //waits for the return value of FadeOut coroutine to commence
        yield return FadeOut;

        Renderer rend = Sphere.transform.GetComponent<Renderer>();
        Color matColor = rend.material.color;
        float alphaValue = rend.material.color.a;


        //while loop to increment object Alpha value until object is opaque
        while(rend.material.color.a < 1f)
        {
            alphaValue += Time.deltaTime / fadeSpeed;
            rend.material.color = new Color(matColor.r, matColor.g, matColor.b, alphaValue);
            yield return null;
        }
        rend.material.color = new Color(matColor.r, matColor.g, matColor.b, 1f);
        StartCoroutine(FadeOut(fadeSpeed));
    }
}
3 Answers

I second Pluto's answer, but I would approach Fade() a little differently:

private IEnumerator Fade()
{
    Renderer rend = Sphere.transform.GetComponent<Renderer>();
    Color initialColor = rend.material.color;
    Color targetColor = new Color(initialColor.r, initialColor.g, initialColor.b, 0f);

    float elapsedTime = 0f;

    while (elapsedTime < fadeDuration)
    {
        elapsedTime += Time.deltaTime;
        rend.material.color = Color.Lerp(initialColor, targetColor, elapsedTime / fadeDuration);
        yield return null;
    }
}

You can, of course, pass in the material and the two colors as arguments. That'd be cleaner. But the logic inside this while loop is, I think, a little easier to understand, as well as more common and ubiquitous, and it lets you explicitly set how long you want the fade animation to take.

Lerp() stands for "linear interpolation". If you're not familiar with it, I suggest you learn it; you'll be using it everywhere.

For example, if you have black as the starting color and white as the target, putting 1/2 as the third argument would get you the shade of gray right in-between; 3/4 would be closer to white, and 1/4 closer to black.

You can use it for colors as Color.Lerp(), but also numbers, vectors, and essentially any value that lives on a spectrum.

You could just write a coroutine that controls the effect:

void Start() => StartCoroutine(FadeInOut());  

IEnumerator FadeInOut()
{
    var material = Sphere.GetComponent<Renderer>().material;
    //forever
    while (true)
    {
        // fade out
        yield return Fade(material, 0);
        // wait
        yield return new WaitForSeconds(fadePause);
        // fade in
        yield return Fade(material, 1);  
        // wait
        yield return new WaitForSeconds(fadePause);
    }
}

IEnumerator Fade(Material mat, float targetAlpha)
{
    while(mat.color.a != targetAlpha)
    {
        var newAlpha = Mathf.MoveTowards(mat.color.a, targetAlpha, fadeSpeed * Time.deltaTime);
        mat.color = new Color(mat.color.r, mat.color.g, mat.color.b, newAlpha);
        yield return null;
    }
}

Your error is here (as I'm sure your stack trace would have shown):

//Fade In Coroutine
public IEnumerator FadeIn(float fadeSpeed)
{
    //waits for the return value of FadeOut coroutine to commence
    yield return FadeOut; // !!! ERROR

You're missing the actual call to the function (the parentheses). I'm not actually sure what you intended with that line... does it need to exist at all?


But honestly, Coroutines are overkill for simple cyclers (in your case, an Alpha cycle). See font size with coroutines for an example.

Related