Reputation: 1580
I want to create some fireflies in Unity. I want to Increase light intensity then wait some seconds and then decrease it in Unity. When they get spawned, I want them increasing their light intensity, wait some seconds and then fade out. How can I create this "process" in a clean way?
private Light pointLight; // The light component of the firefly
private float minLuminosity = 0; // min intensity
private float maxLuminosity = 1; // max intensity
private float luminositySteps = 0.005f; // factor when increasing / decreasing
private float shineDuration = 3; // wait 3 seconds when faded in
private void Start()
{
pointLight = GetComponent<Light>();
pointLight.intensity = Random.Range(minLuminosity, maxLuminosity); // start with a random intensity
StartCoroutine(ChangeIntensity()); // start the process
}
private IEnumerator ChangeIntensity()
{
pointLight.intensity += luminositySteps; // increase the firefly intensity / fade in
yield return new WaitWhile(() => pointLight.intensity >= maxLuminosity); // wait for the maximum intensity
yield return new WaitForSeconds(shineDuration); // wait 3 seconds
pointLight.intensity -= luminositySteps;
yield return new WaitWhile(() => pointLight.intensity <= maxLuminosity); // wait for the minimum intensity
StartCoroutine(ChangeIntensity()); // do it again
}
So obviously the coroutine stops forever at the first WaitWhile()
How can I create such a code chain? When fading in or out, I just mean changing the light intensity.
Upvotes: 2
Views: 6430
Reputation: 125275
Even though this has been solved, the current solutions are just decrementing the variable and also creates new object (WaitForSeconds
) every frame.
The proper way of doing this in Unity is using Mathf.Lerp
and Time.deltaTime
. This type of operation is what Mathf.Lerp
is made for which is to go from your minLuminosity
to maxLuminosity
. You can read more about this in my other question for fading out/in GameObject using its alpha component here.
I took the fadeInAndOut
function from that answer and ported it to work with the Light
component. Here is a simple light fade in/out function:
IEnumerator fadeInAndOut(Light lightToFade, bool fadeIn, float duration)
{
float minLuminosity = 0; // min intensity
float maxLuminosity = 1; // max intensity
float counter = 0f;
//Set Values depending on if fadeIn or fadeOut
float a, b;
if (fadeIn)
{
a = minLuminosity;
b = maxLuminosity;
}
else
{
a = maxLuminosity;
b = minLuminosity;
}
float currentIntensity = lightToFade.intensity;
while (counter < duration)
{
counter += Time.deltaTime;
lightToFade.intensity = Mathf.Lerp(a, b, counter / duration);
yield return null;
}
}
Now, to create the exact effect you want which is to increase light intensity then wait some seconds and then decrease it, create another coroutine function that calls the function above and waits for it to finish. You can do that by yielding the fadeInAndOut
function. Notice how WaitForSeconds
is declared outside the while
loop so that it does not create new Object each time.
//Fade in and out forever
IEnumerator fadeInAndOutRepeat(Light lightToFade, float duration, float waitTime)
{
WaitForSeconds waitForXSec = new WaitForSeconds(waitTime);
while (true)
{
//Fade out
yield return fadeInAndOut(lightToFade, false, duration);
//Wait
yield return waitForXSec;
//Fade-in
yield return fadeInAndOut(lightToFade, true, duration);
}
}
USAGE:
public Light lightToFade;
public float eachFadeTime = 2f;
public float fadeWaitTime = 5f;
void Start()
{
StartCoroutine(fadeInAndOutRepeat(lightToFade, eachFadeTime, fadeWaitTime));
}
Upvotes: 5
Reputation: 2612
The problem in your code was that you applied your luminosity change only once, thus your WaitWhile
condition would never be reached. I would change both WaitWhile
into simple while loops, and then use WaitForEndOfFrame:
private IEnumerator ChangeIntensity()
{
while(true)
{
while(pointLight.intensity <= maxLuminosity)
{
pointLight.intensity += luminositySteps; // increase the firefly intensity / fade in
yield return new WaitForEndOfFrame();
}
yield return new WaitForSeconds(shineDuration); // wait 3 seconds
while(pointLight.intensity > minLuminosity)
{
pointLight.intensity -= luminositySteps;
yield return new WaitForEndOfFrame();
}
}
}
Upvotes: 2
Reputation: 1580
So I got it by using the following while loop
private IEnumerator ChangeIntensity()
{
while (true)
{
pointLight.intensity += isIncreasing ? luminositySteps : -luminositySteps;
if (pointLight.intensity <= minLuminosity)
isIncreasing = true;
if (pointLight.intensity >= maxLuminosity)
{
isIncreasing = false;
yield return new WaitForSeconds(shineDuration);
}
yield return null;
}
}
Upvotes: 0