I have a simple script that spawns some particles when an object gets destroyed (like a projectile).
public class DestructionParticlesScript : MonoBehaviour
{
public GameObject[] particlePrefabs;
void OnDisable()
{
foreach( GameObject particlePrefab in particlePrefabs )
{
// I assume these particles auto-destroy
Instantiate( particlePrefab, transform.position, transform.rotation );
}
}
}
Now, if you stop the game while the particles are active, because they’re not parented to anything (I presume), they would remain in the scene.
That is, until I added this script to the particle prefabs themselves:
public class DestroyOnQuit : MonoBehaviour
{
void OnApplicationQuit()
{
Debug.Log( "Destroying " + name );
Destroy( gameObject );
}
}
Now that works for if the particles are in in the process of playing and you stop the in-editor game.
The problem that I’m running into is that if you quit running the in-editor game while the projectile is in mid-air, the OnDisable gets called for the projectile (spawning the particles), but OnApplicationQuit for the spawned prefabs doesn’t get called, leaving the instantiated clones of the particle prefabs in the scene and the warning “!objects.empty ()”. Is there any way to see if the OnDisable is being caused by the application quitting, or some other workaround so that I don’t have rogue spawned particles cluttering the scene?
I’m using Unity iPhone 1.5 but it happened on earlier versions as well and I presume the non-iPhone versions of Unity.
I just stumbled on a similar issue, but with very different effects…
Using a previous more simplistic version of this Singleton, I had a script with OnDisable to call my Manager.Instance and, some times, it does it after the Instance have been destroyed. That would generate a very weird bug. And so I wanted to “bypass OnDisable on application quit” as well.
Since this is 4 years old you probably solved your question already… Or gave up programming. But, in case anyone stumble here first, like I did, there’s the solution I’ve used (the Singleton script re-edited).
For you case, the solution would be analogously similar. Keep in mind OnDisable is called after OnApplicationQuit. So add a OnApplicationQuit to DestructionParticleScript to set a dirty flag the application is quitting. Something along the lines:
public class DestructionParticlesScript : MonoBehaviour
{
public GameObject[] particlePrefabs;
private bool isApplicationQuitting = false;
void OnDisable()
{
if (isApplicationQuitting) return;
foreach( GameObject particlePrefab in particlePrefabs )
{
// I assume these particles auto-destroy
Instantiate( particlePrefab, transform.position, transform.rotation );
}
}
void OnApplicationQuit () {
isApplicationQuitting = true;
}
}
+1, I just ran into this exact issue with OnDestroy() and the Singleton found on the Unity wiki. Application.IsQuitting would make a lot of sense here.
Is it guaranteed that OnApplicationQuit() will get called before OnDestroy() for all MonoBehaviors? If so, you could implement your own MyApplication class and cache the boolean there, rather than once per MonoBehavior.
I use my own Destroy() methods when practical, and I only just encountered the issue of OnDisable() being called while quitting now. Sadly, I doubt it will make a difference, but I voted anyway.
The Execution Order flowchart is invaluable, but it appears…wrong? OnApplicationQuit() is clearly called before OnDisable(), verified with log statements and as described in the Unify link Cawas posted. In fact, the order is OnApplicationQuit() > OnDisable() > OnDestroy().
But this doesn’t solve the issue of having to manually remember whether the app is quitting. This just adds the ability for us to put our code elsewhere instead of putting it in OnApplicationQuitting method. This callback is only useful if that code is located in an object that isn’t a MonoBehavior. I would have far preferred a boolean instead of an event.
As it stands now, I still have to make a useless method in my MonoBehaviours that only remembers whether the app is quitting so that I can safely unsubscribe from events in OnDestroy. Imagine how often I have to write this useless check, the alternative of which is relatively tedious.
Unity… how hard is it to just implement a bool? It should only take two lines of code. One line for the definition of a property with a private setter, another for setting it to true before calling OnApplicationQuit methods… XD It would literally take less than a minute for any of Unity engineers to add this.
Where do I vote for this since feedback has been shut down?
What I found to be the cleanest workaround for this is to create a static class that subscribes to Application.quitting.
But it would be very nice to have Application.isQuitting bool and I am a bit surprised that there is no such thing in the Unity API
I was having a similar issue instantiating objects in OnDisable.
Was getting the error: Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)
What worked for me was to check if the scene was still loaded in OnDisable. This returned false both when quitting the app/editor and when unloading the scene.
void OnDisable()
{
if(!this.gameObject.scene.isLoaded) return;
// Instantiate objects here
}
Not sure this fully answers the original question but hopefully this helps someone.