- Home /
SceneManager.LoadScene not working ONLY when it is in IEnumerator functions
I've experienced a weird error: when I call SceneManager.LoadScene in any (emphasis on any) IEnumerator function, it doesn't work. Here's an example of what isn't working:
IEnumerator TagDisplay()
{
yield return new WaitForSeconds(updateSpeed);
float tagsActive = GameObject.FindGameObjectsWithTag(tagToSearchFor).Length;
if (tagsActive < 1)
{
tagText.text = ifNoTagsLeft;
yield return new WaitForSeconds(5);
Debug.Log("hi!");
if (setHighScore)
{
setHighScore = false;
highscoreObject.timerStop = true;
Debug.Log("Score set!");
}
//LoadLevel();
if (levelToMoveToElseBlank != "")
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1); //go to next level once enemies are dead
}
else
{
SceneManager.LoadScene(levelToMoveToElseBlank); //go to next level once enemies are dead
Debug.Log("Level loaded!");
}
}
else
{
tagText.text = introString + tagsActive.ToString();
}
StartCoroutine(TagDisplay());
}
Another example of code that doesn't work:
IEnumerator TagDisplay()
{
yield return new WaitForSeconds(updateSpeed);
float tagsActive = GameObject.FindGameObjectsWithTag(tagToSearchFor).Length;
if (tagsActive < 1)
{
tagText.text = ifNoTagsLeft;
yield return new WaitForSeconds(5);
Debug.Log("hi!");
if (setHighScore)
{
setHighScore = false;
highscoreObject.timerStop = true;
Debug.Log("Score set!");
}
LoadLevel();
}
else
{
tagText.text = introString + tagsActive.ToString();
}
StartCoroutine(TagDisplay());
}
void LoadLevel()
{
if (levelToMoveToElseBlank != "")
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1); //go to next level once enemies are dead
}
else
{
SceneManager.LoadScene(levelToMoveToElseBlank); //go to next level once enemies are dead
Debug.Log("Level loaded!");
}
/*
Debug.Log("Level loaded!");
SceneManager.LoadScene(levelToMoveToElseBlank);
*/
}
Strangest of all... this used to work. This code worked in my game and all my other scenes for nearly six weeks. Somehow, I seem to have screwed up every IEnumerator in my project sometime in the last week or two. If I use Debug.Log("hi") in an IEnumerator, it still prints out after a few seconds, but it never runs the scene change after a delay.
Some code I ended up writing that does work (it loads the next level instantly, which is a little jarring):
void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
//FractureManager.collisionNum++;
Destroy(gameObject);
//yield return new WaitForSeconds(0.01f);
/*
brokenPiece1.transform.localScale = originalPiece.transform.lossyScale * 49f;
brokenPiece2.transform.localScale = originalPiece.transform.lossyScale * 49f;
brokenPiece3.transform.localScale = originalPiece.transform.lossyScale * 49f;
brokenPiece4.transform.localScale = originalPiece.transform.lossyScale * 49f;
brokenPiece5.transform.localScale = originalPiece.transform.lossyScale * 49f;
brokenPiece6.transform.localScale = originalPiece.transform.lossyScale * 49f;
brokenPiece7.transform.localScale = originalPiece.transform.lossyScale * 49f;
*/
//clone = brokenPiece.transform.localScale = originalPiece.transform.lossyScale;
if (!shattered)
{
shattered = true;
GameObject clone;
clone = Instantiate(brokenPiece, originalPiece.position, originalPiece.rotation);
clone.transform.GetChild(0).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
clone.transform.GetChild(1).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
clone.transform.GetChild(2).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
clone.transform.GetChild(3).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
clone.transform.GetChild(4).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
clone.transform.GetChild(5).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
clone.transform.GetChild(6).gameObject.transform.localScale = originalPiece.transform.lossyScale * 49;
}
Debug.Log("start new elvel");
highscoreTimer.timerStop = true;
//StartCoroutine(LoadNewLevel());
LoadNewLevel();
}
}
void LoadNewLevel()
{
//yield return new WaitForSeconds(waitAfterHit);
SceneManager.LoadScene(levelName);
}
Any thoughts?
Answer by Namey5 · Sep 07, 2020 at 09:07 AM
SceneManager was kinda built to be run asynchronously - as such, LoadLevel does some weird things with timing and it is recommended you use LoadLevelAsync in most cases. Because you are already calling this from a coroutine, it's even more appropriate;
...
Debug.Log("Score set!");
}
//LoadLevel();
if (levelToMoveToElseBlank != "")
{
yield return SceneManager.LoadSceneAsync(SceneManager.GetActiveScene().buildIndex + 1); //go to next level once enemies are dead
}
else
{
...
https://docs.unity3d.com/ScriptReference/AsyncOperation.html
Really appreciate it! This works! For a little while, I though it wasn't working still, and then I realized that I'd misspelled the level that I wanted to move to. So, that could be a problem for someone else, but in this case, I was legitimately having a problem with the loadScene separate from misspelling. Your solution worked!