Search Unity

[SOLVED] Can Unity's OnDestroy be subscribed to?

Discussion in 'Scripting' started by Deleted User, Dec 20, 2014.

  1. Deleted User

    Deleted User

    Guest

    Can I subscribe to the OnDestroy event?
     
  2. OpticalOverride

    OpticalOverride

    Joined:
    Jan 13, 2013
    Posts:
    161
    What do you mean? Like an event? So you want a script to be able to determine when another script is destroyed? Not sure if this is a built in to Unity's API, but you can fake it I guess.

    Just use the OnDestroy callback as you normally would in a script and then use something like a SendMessage within it to call to the external script (or a list of external scripts). Could clean it up and have any scripts you want the "event" to be called in to inherit from some sort of CustomEvent class maybe (sort of like OnDestroy is a Monobehaviour), and then override a DestroyEvent function from this class. The function would be called any time the "watched" script is destroyed (using the OnDestroy callback as previously described). This is not nearly as clean as the ability to subscribe to an event, but hey, it would work.:p

    There may be an even cleaner way to do this, although I'm not sure how to create a callback in C# at the moment (haven't needed one yet). Maybe look into something like that as well.
     
    Deleted User likes this.
  3. RSG

    RSG

    Joined:
    Feb 20, 2013
    Posts:
    93
    You could do something like:

    Code (CSharp):
    1. class MyClass : MonoBehaviour
    2. {
    3.     private void OnDestroy()
    4.     {
    5.         // Send notification that this object is about to be destroyed
    6.         if(this.OnDestroyEvnt != null) this.OnDestroyEvnt(this);
    7.     }
    8.  
    9.     /// <summary>
    10.     /// This event is invoked when unity is calling OnDestroy
    11.     /// </summary>
    12.     public event OnDestroyDelegate OnDestroyEvnt;
    13.  
    14.     public delegate void OnDestroyDelegate(MonoBehaviour instance);
    15. }
    And then to use it:

    Code (CSharp):
    1.  
    2.  
    3. var myClass = GetComponent<MyClass>();
    4. myClass.OnDestroyEvnt += OnDestroyListener;
    5.  
    6. ...
    7.  
    8. private void OnDestroyListener(MonoBehaviour instance)
    9. {
    10.         // do stuff
    11. }
    12.  
    13.  
     
  4. Deleted User

    Deleted User

    Guest

    OK I guess I have no choice but to create my own events like RSG suggested.
     
    MilenaRocha likes this.
  5. juelzsantana123

    juelzsantana123

    Joined:
    Feb 28, 2019
    Posts:
    17
    Yes this missing this callback by default kinda sucks.
    In my case i run all coroutines on persistent gameObj. But at the same time i want to stop coroutines on caller destroy. Having event could be useful but instead ill create custom evt
    --_(*_*)_--
     
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,836
    There's a good reason why this callback doesn't exist by default. Basically every delegate should be null checked before it's invoked (such as
    myDelegate?.Invoke()
    ), which comes with overhead. It's unnecessary for this to be the case for every single gameObject and should be done on a per implementation basis.
     
    Bunny83 likes this.
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,987
    Exactly! Unity's component system is actually well optimised in this regard. If a MonoBehaviour does not implement a certain magic callback method, Unity won't even try to call it. They essentially do a static analysis of the classes beforehand to see which classes require which callbacks. So creating an event proxy like it was mentioned by RSG 8 years ago is the best approach. Keep in mind that if you're the subscriber, you can use
    GetOrAddComponent on the target and just subscribe to the event.

    That's actually the beauty of a component based system. Functionality is modular. If you need a certain behaviour, you just attach it.
     
  8. koirat

    koirat

    Joined:
    Jul 7, 2012
    Posts:
    2,073
    You can have similar component as below.

    Code (csharp):
    1.  
    2. class DestroyedComponent:Monobehaviour{
    3.  
    4.   public event EventHandler Destroyed;
    5.  
    6.   void OnDestroy(){
    7.       Destroyed?.Invoke(this.EventArgs.Empty)
    8.       Destroyed = null;
    9.   }
    10.  
    11. }
    12.  
    So when you want to subscribe to particular GameObject you can do this.

    Code (csharp):
    1.  
    2.  
    3. var destroyedCmp = go.GetComponent<DestroyedComponent>();
    4. if(destroyedCmp == null){
    5.    destroyedCmp = go.AddComponent<DestroyedComponent>();
    6. }
    7.  
    8. destroyedCmp.Destroyed+=Object_Destroyed;
    9.  
    10.  
    11.  
     
    xaldin-76 likes this.
  9. Maraudical

    Maraudical

    Joined:
    Feb 8, 2021
    Posts:
    7
    I was able to register an action to the destroyCancellationToken like this. It seems to do what you want without even needing to add events into the MonoBehaviour you want to monitor.
    Code (CSharp):
    1. // Reference to the script
    2. [SerializeField] private MonoBehaviour monoBehaviour;
    3.  
    4. private void Start()
    5. {
    6.      monoBehaviour.destroyCancellationToken.Register(OnMonobehaviourDestroyed);
    7. }
    8.  
    9. private void OnMonobehaviourDestroyed() { /*Do stuff*/ }
    10.  
     
    SisusCo and CodeRonnie like this.
  10. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,836
    Important to note this is only a Unity 2022.2+ feature.
     
    Maraudical and CodeRonnie like this.
  11. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    529
    Drat.
     
    patrickjarnfelt likes this.