Can I subscribe to the OnDestroy event?
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.![]()
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.
You could do something like:
class MyClass : MonoBehaviour
{
private void OnDestroy()
{
// Send notification that this object is about to be destroyed
if(this.OnDestroyEvnt != null) this.OnDestroyEvnt(this);
}
/// <summary>
/// This event is invoked when unity is calling OnDestroy
/// </summary>
public event OnDestroyDelegate OnDestroyEvnt;
public delegate void OnDestroyDelegate(MonoBehaviour instance);
}
And then to use it:
var myClass = GetComponent<MyClass>();
myClass.OnDestroyEvnt += OnDestroyListener;
...
private void OnDestroyListener(MonoBehaviour instance)
{
// do stuff
}
OK I guess I have no choice but to create my own events like RSG suggested.
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
–(**)_–
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.
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.
You can have similar component as below.
class DestroyedComponent:Monobehaviour{
public event EventHandler Destroyed;
void OnDestroy(){
Destroyed?.Invoke(this.EventArgs.Empty)
Destroyed = null;
}
}
So when you want to subscribe to particular GameObject you can do this.
var destroyedCmp = go.GetComponent<DestroyedComponent>();
if(destroyedCmp == null){
destroyedCmp = go.AddComponent<DestroyedComponent>();
}
destroyedCmp.Destroyed+=Object_Destroyed;
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.
// Reference to the script
[SerializeField] private MonoBehaviour monoBehaviour;
private void Start()
{
monoBehaviour.destroyCancellationToken.Register(OnMonobehaviourDestroyed);
}
private void OnMonobehaviourDestroyed() { /*Do stuff*/ }
Important to note this is only a Unity 2022.2+ feature.
Drat.
In my case, i want to know if a Collider is getting destroyed and i must know BEFORE it gets destroyed so i can get a reference to that Collider. Even tho we have MonoBehaviour.destroyCancellationToken, there is no point at using it since you cant get what is getting destroyed.
Well, no other choice than fixing Unity’s baddy system. Need solutions, not advice.
Currently, i am thinking of creating a static component that acts like a destroyer pipeline. I will surely post my shitty code here so everybody can upgrade that if they want to ![]()
You can get it on previous versions if you use UniTask. They have an extension method for retrieving the destroy token.