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?
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 Manager class, so I assumed that children of objects that are DontDestroyOnLoad would also be DontDestroyOnLoad. Is that not the case?
The way I've structured the game has the game create a listener object when the game first starts and then I just never have a second listener, so that's how I got around that. After some testing, it appears that even with DDOL objects/scripts, a running coroutine will not continue after a scene load if it was yielding at the time - though I have gotten some inconsistent behavior here. I'll continue to test and experiment, but if anyone has been able to keep coroutines running correctly during a scene change, I'd love the insight! :)
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.
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.
Have you called
– Peter_GDontDestroyOnLoad()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.
– kromenakWell 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
– Ray-PendergraphHmm, well, I haven't made the audio sources and the listener DontDestroyOnLoad, but they are children of the Manager class, so I assumed that children of objects that are DontDestroyOnLoad would also be DontDestroyOnLoad. Is that not the case?
– kromenakThe way I've structured the game has the game create a listener object when the game first starts and then I just never have a second listener, so that's how I got around that. After some testing, it appears that even with DDOL objects/scripts, a running coroutine will not continue after a scene load if it was yielding at the time - though I have gotten some inconsistent behavior here. I'll continue to test and experiment, but if anyone has been able to keep coroutines running correctly during a scene change, I'd love the insight! :)
– kromenak