Detect when GameObject has been deleted / removed from scene

Is there a way to determine when an object has been removed from the scene in the editor (eg the user has selected the object and pressed 'delete').

I would have expected OnDisable() to be called, but it doesn't seem to be.

What I did to detect when an object is destroyed in edit mode is add a custom editor to it. So you create a blank script and attach a custom editor to it. In the custom editor use the OnDestroy method. Now this will get called even if you just deselect the object so in that method you need to check if the target script is null. If it’s null you have deleted the object. So when you run the game since this is just for the unity editor you can tell it to remove this component at run time if you want. Here are the scripts :

using UnityEngine;
using System.Collections;

public class ObjectChecker : MonoBehavior
{
     //Nothing needed here
}

using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(ObjectChecker))]
public class ObjectChecker : Editor
{
    public void OnDestroy()
    {
        if ( Application.isEditor )
        {
            if(((ObjectChecker)target) == null)
                //Do your code here
        }
    }
}

Now this is a custom class for checking if the object is destroyed. You can put this OnDestroy code in any of your custom editor scripts if you want it to do something before the object is destroyed. This works for me with no issues. I use it in allot of my custom editors.

Using ExecuteInEditMode and OnDestroy wont completely solve the issue. Because OnDestroy is also called when you hit play button in editor.
For explicit detection of users deleting gameobject, my solution is:

For example, we have a xxx.cs monobehaviour attach to the gameobject that we wanna have deletion detection. Implement a corresponding editor script of xxx.cs like xxx_editor.cs (if you dont know how to do this, look at this tutorial link text)

in this xxx_editor.cs implement :

void OnSceneGUI(){
	if (Event.current.commandName=="Delete") Debug.Log(target.name +" is deleted");
}

now you can easily detect gameobject deletion right in side the editor script, however it might be triggered multiple times because OnSceneGUI is called multiple times a frame. but I am sure that’s easy to solve.

PS: it only detect deletion in Scene view, if deletion happens in hierarchy, then it doesnt work. prbly need to use EditorApplication.hierarchyWindowChanged

Your script must have ExecuteInEditMode attribute for that event to fire.

This will allow OnEnable, OnDisable etc be called when objects are created, when the game is run, stopped and object being deleted.

  • Note that adding this attribute might cause other problems since other methods might be called as well, depending on your script. Read the docs.

This works for detecting deleted objects in scene and hierarchy.

[ExecuteInEditMode]
public class MyClass : MonoBehaviour
{
	void OnDestroy ()
	{
		if (Event.current != null && Event.current.commandName == "Delete")
			DoStuffBeforeDie ();
	}
}

@Damyan I’ve been looking for a solution for a similar purpose. I am building a GUI system where GUI elements are actual 3D objects with procedural generated meshes. I need to mark a parent object as being dirty and clean up stuff for developers while they are using the GUI elements in Edit Mode (Or in Play Mode). By Designing my MonoBehaviors to use ExecuteInEditMode from the start, I’ve been able to use onDisable() on the actual object (not a custom editor instance) to detech when the developer is deleting this from the hierarchy (in edit or play mode) and also if they disable the script. In either case causing a re-generation of the GUI meshes. Perhaps you cannot apply this knowledge.

Good Luck!

Extending on @slkjdfv’s answer, there is one slight problem with the solution. When application play is terminated, the OnDestroy method gets called too. To overcome this problem, I implemented and tested this solution:

[CustomEditor(typeof(MyObject))]
public class MyObjectEditor : Editor
{
    private bool mRunningInEditor;

    private void OnEnable()
    {
        mRunningInEditor = Application.isEditor && !Application.isPlaying;
    }

    public override void OnInspectorGUI()
    {
        // do the magic here
    }

    public void OnDestroy()
    {
        if (mRunningInEditor && target == null)
            // Code here for the actual object removal
    }
}

The following code can be placed directly into MonoBehavior, will allow you to get a callback, even though object was “technically deleted”.
But, you are not allowed to use anything like this.gameObject or this.transform etc.

However, you could use this to “clean-up” any entries from your singletons, static classes or Scriptable objects who were pointing at this, etc (their references to it will be ‘null’, meaning their Lists or Dictionaries might contain null entries).

#if UNITY_EDITOR
   //tells if we have already hooked-up to the SceneView delegate, once, some time ago 
   [System.NonSerialized]
   bool linked_SV = false;

   public void OnDrawGizmos() {
        if(linked_SV == false) {
            linked_SV = true;
            SceneView.onSceneGUIDelegate -= OnSceneDraw;
            SceneView.onSceneGUIDelegate += OnSceneDraw;
        }
    }


    void OnSceneDraw(SceneView sceneView) {

        try {
            this.gameObject.name = this.gameObject.name;
        }
        catch{
            SceneView.onSceneGUIDelegate -= OnSceneDraw;
            // this gameObject was destroyed. 
             OnDestroy();
             SomeOtherFunction();
            return;
        }
 #endif

For example, I was using Graphics.DrawMesh, from within my OnSceneDraw(), and was successfully able to “unhook” my function from the SceneView.OnSceneViewDelegate, even after unity said it was deleted.

This was possible since unity “fakes the object’s deletion”, by substituting its own, special, “NULL-value”.
That’s why after destroying any gameObject, it’s also best to set the references to null, manually.
Garbage collector will then remove it.

Final solution based on rklaus’ answer:

[CustomEditor(typeof(MyClass))]
public class MyClassEditor : Editor
{
    public void OnDestroy()
    {
        if (Application.isEditor && !Application.isPlaying && target == null)
        {
            Debug.Log("DESTROYED!");
        }
    }
}

I do not know any official solution. I suggest you to create a component script which implements Destroy() class method and contains Destroying event (code was not tested, sorry).

public delegate void DestroyingHandler( object sender, EventArgs e );

class DestroyHelper: MonoBehaviour
{
    public event DestroyingHandler Destroying = null;

    public static void Destroy( Component component )
    {
        DestroyHelper.Destroy( component.gameObject );
    }

    public static void Destroy( GameObject gameObject )
    {
        DestroyHelper helper = gameObject.GetComponent<DestroyHelper >();

        // Raise event if helper was provided.
        if ( helper != null )
            helper.OnDestroying();

        // Call original destroy method.
        Object.Destroy( gameObject );
    }

    // Raises Destroying event.
    // You can override it in inherited classes.
    protected virtual OnDestroying()
    {
        DestroyingHandler eh = Destroying;
        if ( eh != null )
            eh( this, EventArgs.Empty );
    }
}

But this won't help you in editor unless you will write your own menu command for deleting objects.

As you can see it is possible to use DestroyHelper.Destroy() method to destroy any objects even those not containg DestroyHelper component.

This is so painful. I have a game object which procedurally generates meshes and materials in edit mode. If I remove the gameobject it leaks the meshes and materials. I either have to press a button to destroy the mesh first or I have to just let the objects leak, which then gives me that infinite error message about cleaning up leaked objects, which are not actually being cleaned up otherwise the error message would stop.