- Home /
Running Coroutines Between Levels
Hey everyone,
Ran into an issue with coroutines, hopefully I can get some idea if what I'm trying to do is possible.
I have a coroutine that plays a sequence of audio clips. It will play one, yield until it completes, and then play the next, and then ultimately loop the sequence.
The problem I'm having is that it seems like changing the level while the coroutine is yielding, waiting for the track to finish, seems to cause the coroutine to stop functioning properly. I can receive no debug messages from the coroutine, and the music stops playing instead of continuing. This also seems to crash the editor, and produce an error code "m_instance == 0" - not much to go on with that message.
Has anyone ran into similar issues, found workarounds, have a way I can accomplish this sort of functionality?
Have you called DontDestroyOnLoad()
on the game object that manages audio?
Ah sorry, forgot to mention it. DontDestroyOnLoad is called on the game object, so it does persist between scenes.
Well the source, the listener and the thing playing the sound (if it's a coroutine) have to be DontDestroyOnLoad. It just hit to me that you were talking about sound... splashes are a little simpler. Not even sure how that would work with the listener. http://unity3d.com/support/documentation/Components/class-AudioListener.html
Hmm, well, I haven't made the audio sources and the listener DontDestroyOnLoad, but they are children of the $$anonymous$$anager class, so I assumed that children of objects that are DontDestroyOnLoad would also be DontDestroyOnLoad. Is that not the case?
Well, sounds like you have taken all the proper steps. According to the docs anything under a DDOLed object will not be destroyed either... I suppose you could verify in the editor. I know that loading a scene causes components to temporarily become disabled momentarily even if they are DDOL this may cause some interruption on the Source. Usually if I DDOL the Listener it starts spam$$anonymous$$g the log as there can only be one... this transition from from the listener in one scene to the listener in another might be the culprit. If you figure out what's going on please post back, this is an interesting problem.
Answer by kromenak · Sep 08, 2011 at 05:26 PM
Ultimately, running a coroutine between levels like this did not work out for my needs. There was some very odd behavior where it seemed to work some times, but not the others.
What I ended up doing was using the MonoBehavior's Update method rather than a coroutine to get around the problem all together. Since the MonoBehavior was DontDestroyOnLoad, class variables persisted between levels.
I then took advantage of OnDisable and OnEnable to compensate for variable discrepancies between levels. For example, I had a variable that was counting down the time before the current music track was over and should switch to the next music track. Since music continues playing between levels, this timer gets out of sync with the music time. I used OnEnable to resync this variable using AudioSource.time.
Answer by Ray-Pendergraph · Aug 31, 2011 at 11:26 AM
Yeah, I am pretty sure that we have run into this... it just stops working. Coroutines are ultimately tied to a MonoBehaviour at some point. When you do a regular scene load (not an additive scene) all the game objects not marked DontDestroyOnLoad are wiped out. Along with them their MonoBehaviours and therefore their coroutines.
We usually keep a MonoBehaviour in the game that is accessible as a singleton and is DDOL. This way we can launch Coroutines for tasks like audio clips and intra-scene splash animations from anywhere in the code without having to have a MonoBehaviour or dummy game object and it fixes the odd behavior you mentioned.
Answer by Gotal_D · Nov 27, 2018 at 10:46 AM
You can find the button by name, get the Button component off of it and invoke an event. I use this for reloading and starting my game.
public IEnumerator Reload()
{
UnityEngine.SceneManagement.SceneManager.LoadScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex);
yield return new WaitForSeconds(1f);
GameObject.Find("/StartScreenCanvas/StartPanel/StartGameButton/StartGame").GetComponent<Button>().onClick.Invoke();
}
This is a really dirty way of doing it but it gets the job done. Hope it helps (after 7 years =D)
Answer by Ziplock9000 · Dec 07, 2020 at 05:18 AM
It's because your co-routine code goes out of scope and is unloaded when you load in other scenes.
Your answer
Follow this Question
Related Questions
Loading Level 1 Answer
"Reset Level", Application.LoadLevel 1 Answer
Use the GUITexture to go to the next scene 1 Answer
Move my entire player gameobject in the next scene (using loadlevel) 1 Answer
Load Level on Collision 1 Answer