- Home /
Starting a Coroutine in Update acting differently in play mode and built game
I am trying to make my game fade in and fade out with Coroutine. Fading in ran as it should do but for fading out, it runs as it should in play mode but after I build and run my game, it look like the Update function keep calling StartCoroutine () again and again. I don't know why it runs smoothly in play mode but doesn't in build and run. My code is shown below. (The update function and fadeOut is from a separate scripts)
public float LoadOutTime = 1.2f;
public FadingInOut FadingInOut;
private bool Out;
void Awake (){
Out = false;
}
void Update () {
if (Out == false && Time.time > LoadOutTime) {
FadingInOut.StartCoroutine("FadeOut");
Out = true;
}
}
And FadeOut Coroutine is from another script.
public class FadingInOut : MonoBehaviour {
public float fadeSpeed = 1.1f;
public Color fadeColor;
public string nextLevel;
public bool fadingOut = false;
private RectTransform rect;
private float time;
private Image imageContainer;
void Awake(){
time = Time.time;
imageContainer = GetComponentInChildren<Image> ();
rect = imageContainer.GetComponent<RectTransform> ();
imageContainer.color = fadeColor;
rect.localScale = new Vector3 (1, 1, 1);
}
public IEnumerator FadeOut(){
time = 0.0f;
rect.localScale = new Vector3 (1, 1, 1);
while (imageContainer.color != fadeColor) {
time += Time.deltaTime;
imageContainer.color = Color.Lerp (Color.clear,fadeColor, fadeSpeed*time);
yield return new WaitForSeconds(0.02f);
}
Application.LoadLevel (nextLevel);
}
}
Thanks in advance.
Answer by Xarbrough · Dec 19, 2015 at 05:26 PM
Maybe this helps:
public class SceneManager : MonoBehaviour { [SerializeField] private Image m_FadeImage;
[SerializeField, Tooltip("Time in seconds it takes to complete the screen fade.")]
private float m_Duration = 1.5f;
[SerializeField]
private Color m_TargetColor = Color.black;
private void Start()
{
StartCoroutine(OnSceneFadeIn());
}
/// <summary>
/// Fades out the fade image from it's current color to fully transparent.
/// </summary>
/// <returns></returns>
private IEnumerator OnSceneFadeIn()
{
m_FadeImage.color = m_TargetColor;
Color startColor = m_FadeImage.color;
float elapsedTime = 0f;
while (elapsedTime < m_Duration)
{
m_FadeImage.color = Color.Lerp(startColor, Color.clear, elapsedTime / m_Duration);
elapsedTime += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
m_FadeImage.color = Color.clear;
yield return null;
}
/// <summary>
/// Fades in the fade image over duration seconds and then loads a scene by the given name.
/// </summary>
/// <param name="sceneName">The scene you wish to load.</param>
public void LoadScene(string sceneName)
{
if (string.IsNullOrEmpty(sceneName))
throw new System.ArgumentException("LoadScene must have a valid scene name passed.", "name");
StopAllCoroutines();
StartCoroutine(LoadScene_Internal(sceneName));
}
private IEnumerator LoadScene_Internal(string sceneName)
{
float elapsedTime = 0f;
while (elapsedTime < m_Duration)
{
m_FadeImage.color = Color.Lerp(Color.clear, m_TargetColor, elapsedTime / m_Duration);
elapsedTime += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
m_FadeImage.color = m_TargetColor;
//Application.LoadLevel(sceneName);
UnityEngine.SceneManagement.SceneManager.LoadScene(sceneName);
yield return null;
}
Thanks. It really worked. Was it because of something wrong in my while loop?
I can't tell exactly why it works in the editor and not in build, but one thing that causes trouble is while color != color, and then you lerp. Since the color components are floats and you're never going to perfectly hit a target value with lerp, you might not ever ter$$anonymous$$ate the loop. So then you have a couple of infinitely running coroutines, which do nothing, but may cause other weird behaviour. The way my script does it, is just a little more robust, I think. The important pattern is, that before starting a new coroutine, I stop all other routines on that $$anonymous$$onoBehaviour, just to make sure that I don't end up with multiple ones. Or you can also create a bool variable isRunning and only start a new one, if the old one has finished. And then I'd rather track time progress in seconds than lerp over start until target color is reached, just because it's more clear, how long it will take and easy to ter$$anonymous$$ate that way.