Fade out / fade in scene w/ loading screen
I've got a (very simple?) requirement I just can't get to work, even though it's been covered by numerous tutorials and how-to's on the web. Basically, I want to transition between individual scenes with a black fade in/fade out. Here's my setup:
At the beginning of the game, I have some sort of 'kick-off' scene. It's nothing more than an empty scene with (for testing purposes) red background an an 'init' script which looks like this (pseudo):
Awake:
StartCoroutine(LoadTitleScene());
LoadTitleScene:
SceneController.Instance.LoadScene("TitleScene");
The SceneController
is a singleton service which handles all the scene loading and transition stuff. Here's the code (excerpt):
// SceneController : SingletonMonoBehavior<SceneController>
private ScreenFadeHelper _screenFadeHelper;
private AsyncOperation _sceneLoadOperation;
public void Awake() {
_screenFadeHelper = ScreenFadeHelper.Instance;
}
public void LoadScene(string sceneName) {
StartCoroutine(LoadSceneAsync(sceneName));
}
private IEnumerator LoadSceneAsync(string sceneName) {
// display loading scene
{
_screenFadeHelper.BeginFadeIn(0.5f);
while(_screenFadeHelper.IsFading)
yield return new WaitForEndOfFrame();
SceneManager.LoadScene("LoadingScene");
_screenFadeHelper.BeginFadeOut(0.5f);
while(_screenFadeHelper.IsFading)
yield return new WaitForEndOfFrame();
}
// some other stuff..
// load actual scene
{
// clear unused assets
yield return Resources.UnloadUnusedAssets();
_sceneLoadOperation = SceneManager.LoadSceneAsync(sceneName);
_sceneLoadOperation.allowSceneActivation = false;
while(_sceneLoadOperation.progress < 0.9f)
{
// update progress & stuff
yield return null;
}
_screenFadeHelper.BeginFadeIn(0.5f);
while (_screenFadeHelper.IsFading)
yield return new WaitForEndOfFrame();
_sceneLoadOperation.allowSceneActivation = true;
_screenFadeHelper.BeginFadeOut(0.5f);
while (_screenFadeHelper.IsFading)
yield return new WaitForEndOfFrame();
}
}
And the code for the screen fader (e.g. fade in):
public void BeginFadeIn(float duration)
{
if (IsFading)
return;
IsFading = true;
StartCoroutine(FadeInAsync(duration));
}
private IEnumerator FadeInAsync(float duration, Color color)
{
var alpha = 0.0f;
while (alpha < 1.0f) {
yield return new WaitForEndOfFrame();
if (!IsPaused)
alpha = Mathf.Clamp01(alpha + Time.deltaTime / duration);
DrawQuad(Color.black, alpha);
}
IsFading = false;
}
private static void DrawQuad(Color color, float alpha)
{
color.a = alpha;
GL.PushMatrix();
GL.LoadOrtho();
GL.Begin(GL.QUADS);
GL.Color(color);
GL.Vertex3(0, 0, -1);
GL.Vertex3(0, 1, -1);
GL.Vertex3(1, 1, -1);
GL.Vertex3(1, 0, -1);
GL.End();
GL.PopMatrix();
}
The basic idea is this:
1. Fade in a black quad on the whole screen
2. Load the 'loading scene'
3. Fade out the black quad
4. Asynchronously load the actual scene
5. Fade in a black quad on the whole screen
6. Activate the actual scene
7. Fade out the black quad
Long story short: The whole thing just flickers, and then the actual scene pops up. No fading at all (in build). And in the editor, the same thing happens, except the last fade-in doesn't seem finished (there's a semi-transparent black overlay over the whole screen).
What doesn't work here? Is there a problem with the co-routines?