Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Coroutine on Don't Destroy On Load stops running

Discussion in 'Scripting' started by LMichelle, Dec 14, 2020.

  1. LMichelle

    LMichelle

    Joined:
    Mar 10, 2018
    Posts:
    10
    Hi there,

    I'm new to loading scenes. The scenario is this; on a field level, I bump into a monster. OnCollisionEnter sends a message to a GameManager that is on a Don't Destroy on Load gameobject.
    The GameManager's coroutine that is called is as following:
    Code (CSharp):
    1.     public IEnumerator StartBattle(List<GameObject> enemies)
    2.     {
    3.         UnityEngine.SceneManagement.SceneManager.LoadScene("Battle Scene");
    4.         yield return new WaitForSecondsRealtime(.5f);
    5.         Debug.Log("Does the app reach here?"); // Doesn't reach here
    6.         BattleSystem battleSystem = GameObject.FindGameObjectWithTag("Battle System").GetComponent<BattleSystem>();
    7.      
    8.  
    9.  
    10.         yield break;
    11.     }
    It will execute the Load Scene, and the wait. If I remove the wait it will give me a bug that it can't find the BattleSystem (presumably because the new scene hasn't quite loaded yet). So, I added the wait.
    However, the coroutine does not continue running after that. The Debug.Log("Does the app reach here") is never called. I'm stumped; this thing is on a DDOL object yet stops.

    I saw some video's on scene loading and I can't work with constants here, nor playerprefs as it's a Windows program. Do I really have to save things in between scenes or am I missing a way that this coroutine can keep running?
     
  2. LMichelle

    LMichelle

    Joined:
    Mar 10, 2018
    Posts:
    10
    I got the wanted behaviour without a coroutine. I now use an enumerator that keeps the state of the Game.
    Code (CSharp):
    1. public enum GameState { FIELD, BATTLEINIT, BATTLE}
    I use an update function to check the state in the gamemanager.
    If the state is BATTLEINIT, it will call a function. The function first checks whether the active scene is the battle scene, otherwise it returns.
    When the function has properly executed it sets its state to Battle.
    Update Method:
    Code (CSharp):
    1.  private void Update()
    2.     {
    3.         switch (GameState)
    4.         {
    5.             case GameState.FIELD:
    6.                 break;
    7.             case GameState.BATTLEINIT:
    8.                 SendToBattle();
    9.                 break;
    10.             case GameState.BATTLE:
    11.                 break;
    12.             default:
    13.                 break;
    14.         }
    15.     }
    Code (CSharp):
    1. private void SendToBattle()
    2.     {
    3.         var currentScene = SceneManager.GetActiveScene();
    4.         if (currentScene != SceneManager.GetSceneByName("Battle Scene"))
    5.             return;
    6.      
    7.         BattleSystem battleSystem = GameObject.FindGameObjectWithTag("Battle System").GetComponent<BattleSystem>();
    8.         Debug.Log("Executing");
    9. }
    It's definitely not the best way to do it as SendToBattle will get called many times... But it's the best solution I came up with. Found a lot of 'answers' including using OnEnable and OnDisable, which doesn't work. This does.
     
  3. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,061
    I suspect you've used the OnCollisionEnter's script's
    StartCoroutine
    instead of the GameManager's.

    i.e. the difference between
    Code (CSharp):
    1. void OnCollisionEnter(Collision collision)
    2. {
    3.     // This starts the coroutine on the current script
    4.     StartCoroutine(GameManager.Instance.SendToBattle());
    5.     // This starts the coroutine on the game manager
    6.     GameManager.Instance.StartCoroutine(GameManager.Instance.SendToBattle());
    7. }
    In doesn't matter which class the coroutine method is defined on, it only matters which MonoBehaviour's
    StartCoroutine
    is called. If you start the coroutine on a script that is then unloaded during scene load, the coroutine will be stopped silently.
     
    vmjunior_, FlyingFeesh and LMichelle like this.
  4. LMichelle

    LMichelle

    Joined:
    Mar 10, 2018
    Posts:
    10
    Thanks, I will try that out as well! I find it quite weird behaviour though, that apparently the program remembers where something started. I thought that as soon as it was fired it just keeps to itself. Thank you!