Search Unity

Possible to bypass OnDisable() on application quit?

Discussion in 'Scripting' started by Tetrad, Sep 1, 2009.

  1. Tetrad

    Tetrad

    Joined:
    Jul 22, 2009
    Posts:
    45
    I have a simple script that spawns some particles when an object gets destroyed (like a projectile).

    Code (csharp):
    1.  
    2. public class DestructionParticlesScript : MonoBehaviour
    3. {
    4.     public GameObject[] particlePrefabs;
    5.    
    6.     void OnDisable()
    7.     {
    8.         foreach( GameObject particlePrefab in particlePrefabs )
    9.         {
    10.             // I assume these particles auto-destroy
    11.             Instantiate( particlePrefab, transform.position, transform.rotation );         
    12.         }
    13.     }
    14. }
    15.  
    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:

    Code (csharp):
    1.  
    2. public class DestroyOnQuit : MonoBehaviour
    3. {
    4.     void OnApplicationQuit()
    5.     {
    6.         Debug.Log( "Destroying " + name );
    7.         Destroy( gameObject );
    8.     }
    9. }
    10.  
    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.
     
  2. Cawas

    Cawas

    Joined:
    Jan 14, 2010
    Posts:
    121
    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:

    Code (csharp):
    1.  
    2. public class DestructionParticlesScript : MonoBehaviour
    3. {
    4.     public GameObject[] particlePrefabs;
    5.     private bool isApplicationQuitting = false;
    6.    
    7.     void OnDisable()
    8.     {
    9.         if (isApplicationQuitting) return;
    10.  
    11.         foreach( GameObject particlePrefab in particlePrefabs )
    12.         {
    13.             // I assume these particles auto-destroy
    14.             Instantiate( particlePrefab, transform.position, transform.rotation );          
    15.         }
    16.     }
    17.  
    18.     void OnApplicationQuit () {
    19.         isApplicationQuitting = true;
    20.     }
    21. }
    22.  
     
    Last edited: Oct 21, 2013
  3. dbanfield

    dbanfield

    Joined:
    Apr 20, 2013
    Posts:
    8
    It may have been four years old but this saved me a lot of head scratching!
    Thanks Cawas!
     
    Cawas likes this.
  4. Cawas

    Cawas

    Joined:
    Jan 14, 2010
    Posts:
    121
    Cool! You're very welcomed! :)
     
  5. KyleStaves

    KyleStaves

    Joined:
    Nov 4, 2009
    Posts:
    820
    I'm really surprised we still don't have an Application.IsQuitting bool so we don't need to manually cache this.
     
    ModLunar, DonLoquacious and Mycroft like this.
  6. imtrobin

    imtrobin

    Joined:
    Nov 30, 2009
    Posts:
    1,545
    yes, I'm surprised too.
     
  7. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    110
    +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.

    EDIT: According to this picture http://docs.unity3d.com/Manual/ExecutionOrder.html it looks like OnDestroy() gets called before OnApplicationQuit(), so this does need to be cached once per MonoBehavior (sigh).

    EDIT2: If you feel this would be a useful feature, please vote for it here: http://feedback.unity3d.com/suggestions/applicationisquitting-flag-to-d
     
    Last edited: Jul 23, 2014
    ModLunar and Cawas like this.
  8. BrianCrandell

    BrianCrandell

    Joined:
    Apr 3, 2013
    Posts:
    65
    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().
     
    Mycroft and Cawas like this.
  9. Mycroft

    Mycroft

    Joined:
    Aug 29, 2012
    Posts:
    160
    The Diagram must have been updated at some point because it now follows the order you suggest that it followed.
     
  10. Baumkuchen

    Baumkuchen

    Joined:
    Feb 14, 2016
    Posts:
    8
    Does anyone know if there is news?
     
  11. shottogan

    shottogan

    Joined:
    Feb 25, 2015
    Posts:
    3
  12. Remiel

    Remiel

    Joined:
    Oct 17, 2012
    Posts:
    101
    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?
     
    ModLunar likes this.
unityunity