user2395639
user2395639

Reputation:

Unity Script: How to gradually change a color of an object using color.lerp?

So i have a button that is suppose to change a colour of an object. Im using color.lerp but i need it to gradually change. like slowly. what i have now:

public Renderer engineBodyRenderer;
public float speed;
public Color startColor, endColor;
float startTime;

// Start is called before the first frame update
void Start()
{
    startTime = Time.time;
    ChangeEngineColour();
}

public void ChangeEngineColour()
{
    float t = (Time.time - startTime) * speed;
    engineBodyRenderer.material.color = Color.Lerp(startColor, endColor, t);
}

so the color of the object does change just not slowly. what am i missing?

Upvotes: 2

Views: 8223

Answers (3)

euleristheendboss
euleristheendboss

Reputation: 1

For this sort of thing I find it best to set the duration instead of using a speed variable.

public Renderer engineBodyRenderer;
public Color startColor, endColor;
public float duration;

private Coroutine changeEngineColorCoroutine;

private void Start()
{
    if (changeEngineColorCoroutine != null)
        StopCoroutine(changeEngineColorCoroutine);

    changeEngineColorCoroutine = StartCoroutine(ChangeEngineColor(startColor, endColor, duration));
}

private IEnumerator ChangeEngineColor(Color _startColor, Color _endColor, float _duration)
{
    // start tick 0f so that startColor is shown for a frame
    float tick = 0;
    while (tick < 1f)
    {
        // Update color
        engineBodyRenderer.material.color = Color.Lerp(_startColor, _endColor, tick);

        // Iterate tick after adjusting color so Lerp doesn't use a tick over 1f
        tick += Time.deltaTime / _duration;

        // Wait a frame
        yield return null;
    }
    // Ensure that the endColor is applied before exit
    engineBodyRenderer.material.color = _endColor;
}

Also, if you were calling ChangeEngineColor after Start(), you could initialise tick already iterated for an instantaneous color transition startup as long as startColor is the color already set on the engine.

float tick = Time.deltaTime / _duration;

Upvotes: 0

Mark Suter
Mark Suter

Reputation: 21

And to change back and forth between colors gradually, replace this line from Fredrick:

engineBodyRenderer.material.color = Color.Lerp(startColor, endColor, tick);

to this:

engineBodyRenderer.material.color = Color.Lerp(startColor, endColor, Mathf.PingPong(Time.time, 1));

So you will have:

enter image description here

Upvotes: 1

Fredrik
Fredrik

Reputation: 5108

In your solution the method is only run ONCE, so only ONE color change can happen. Here's how I usually do it:

void Start() 
{
    // ... your other stuff 

    StartCoroutine(ChangeEngineColour());
}

private IEnumerator ChangeEngineColour()
{
    float tick = 0f;
    while (engineBodyRenderer.material.color != endColor)
    {
        tick += Time.deltaTime * speed;
        engineBodyRenderer.material.color = Color.Lerp(startColor, endColor, tick);
        yield return null;
    }
}

By starting a Coroutine this code will run asyncronously beside the rest of the code and with yield return null it will loop in the same speed as your Update() functions, so essentially you've created an isolated Update() method, that run every frame and will gradually change the color every frame.

Upvotes: 3

Related Questions