Home > Software engineering >  Running coroutine for lerping color
Running coroutine for lerping color

Time:08-12

I have a coroutine where I am lerping to change a color from white to red. It works but it happens only once as the coroutine is run only once.

I want this to happen two or three times like a ping pong, without running the coroutine multiple times (as that would not be feasible).

It should lerp from white to red, then red to white and then again white to red in the end. Is there a way to do this in the coroutine shown below?

bool changingColor = false;

void Start(){
 StartCoroutine(LerpColor(this.GetComponent<MeshRenderer>(), Color.white, Color.red, 0.5f));
}

IEnumerator LerpColor (MeshRenderer mesh, Color fromColor, Color toColor, float duration) {
        if (changingColor) {
            yield break;
        }
        changingColor = true;
        float counter = 0;

        while (counter < duration) {
            counter  = Time.deltaTime;

            float colorTime = counter / duration;
            Debug.Log (colorTime);

            //Change color
            mesh.material.color = Color.Lerp (fromColor, toColor, counter / duration);
            //Wait for a frame
            yield return null;
        }
        changingColor = false;
    }

CodePudding user response:

Couldn't you just do something like this?:

IEnumerator LerpColor (MeshRenderer mesh, Color fromColor, Color toColor, float duration, int repetitions) {
    if (changingColor) {
        yield break;
    }
    changingColor = true;
    for (int i = 0; i < repetitions;   i) {
        float counter = 0;

        while (counter < duration) {
            counter  = Time.deltaTime;

            float colorTime = counter / duration;
            Debug.Log (colorTime);

            //Change color
            mesh.material.color = Color.Lerp (fromColor, toColor, counter / duration);
            //Wait for a frame
            yield return null;
        }
        Color tmp = fromColor;
        fromColor = toColor;
        toColor = tmp;
    }
    changingColor = false;
}

And call it like this?:

StartCoroutine(LerpColor(this.GetComponent<MeshRenderer>(), Color.white, Color.red, 0.5f, 4));

Or if you want to keep your method as it is, perhaps you could create a wrapper around it:

IEnumerator LerpColorRepeater(MeshRenderer mesh, Color fromColor, Color toColor, float repetitionDuration, int repetitions) {
    for (int i = 0; i < repetitions;   i)
    {
        IEnumerator lerpColorEnumerator = LerpColor(mesh, i % 2 == 0 ? fromColor : toColor, i % 2 == 0 ? toColor : fromColor, repetitionDuration, repetitions);
        while (lerpColorEnumerator.MoveNext())
        {
            yield return lerpColorEnumerator.Current;
        }
    }   
}

Usage:

StartCoroutine(LerpColorRepeater(this.GetComponent<MeshRenderer>(), Color.white, Color.red, 0.5f, 4));

CodePudding user response:

It can be done much simpler by using Mathf.PingPong

void Update() {
  mesh.material.color =
      Color.Lerp(Color.white, Color.red, Mathf.PingPong(Time.time, 1));
}

CodePudding user response:

There's nothing actually wrong with DiplomacyNotWar's approach, but there's a much simpler way:

  • Warp the mixing factor through a periodic function

I also switched the loop to a for loop since you had all the classic for-loop steps.

IEnumerator PingPongColor (MeshRenderer mesh, Color fromColor, Color toColor, float duration, float durationEachPass) {
    if (changingColor) {
        yield break;
    }
    changingColor = true;
    for (float t = 0.0f; t < duration; t  = Time.deltaTime) {
        float colorTime = t / durationEachPass;
        float mix = 0.5f * (1.0f - (float)Math.Cos(Math.PI * colorTime));
        Debug.Log($"colorTime={colorTime} mix={mix}");

        //Change color
        mesh.material.color = Color.Lerp(fromColor, toColor, mix);

        //Wait for a frame
        yield return null;
    }
    changingColor = false;
}

How it works:

  1. The cosine function smoothly changes from 1.0 to -1.0 in Pi radians. So 1 - cos(t * Pi) smoothly changes from 0.0 to 2.0 in 1.0 input units.

  2. An extra factor of 0.5 gives us a smooth change from 0.0 to 1.0 in 1.0 input units.

  3. Cosine is symmetric and periodic, after reaching -1.0, it starts smoothly increasing back to 1.0. So our (1 - cos(t * Pi))/2 reverses at the same time, but it reached 1.0 and then returns smoothly to zero, then reverses again.

I would however recommend one additional change, to separate the calculation of the color sequence from the application to the mesh.

  • Related