0
\$\begingroup\$

I have a script that destroys the player object when a collider with that script touches it. The thing is that, even if there is no time specified in the script, it takes couple seconds before it destroys the player. Why does this happen, and how do I get around it?

public class DestroyScript : MonoBehaviour 
{
    public GameObject player;

    void OnTriggerEnter(Collision otherObj)
    {
        if (otherObj.gameObject.tag == "Player")
            Destroy(player);
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ It's because Destroy called on a GameObject will Invoke Destroy on each of the Components and Objects held by this GameObject try to make an Coroutine which will destroy Components one by one instead of all at once. \$\endgroup\$ – Mateusz Feb 8 '17 at 19:45
  • \$\begingroup\$ Thanks. Anyway , I changed my code to : public class DestroyScript : MonoBehaviour { public GameObject player; // Use this for initialization void Start () { } // Update is called once per frame void OnTriggerEnter(Collider otherObj) { if(otherObj.gameObject.tag == "Player") Destroy(otherObj.gameObject); } \$\endgroup\$ – Mihai Barbu Feb 8 '17 at 19:52
  • \$\begingroup\$ You cannot "destroy" an object in a managed environment. The most Unity can do is set the object to null, along with every child entity it owns. This leads me to believe that your design is fatally flawed, much as your understanding is of how Unity works. I'm downvoting for blatant lack of personal research, \$\endgroup\$ – Krythic Feb 9 '17 at 0:41
  • \$\begingroup\$ @Krythic, the question specifically only asks about calling 'Destroy()' on the object. I think it is safe to assume that this functionality is the expected functionality when the asked reports "destroying the player". You can do this quite easily, in Unity. If your still confused, I can link some basic tutorials or examples that demonstrate this. \$\endgroup\$ – Gnemlock Feb 9 '17 at 11:21
  • \$\begingroup\$ @Krythic, it appears to me that you may be the one who misunderstands Unity's workings. The GameObject that our managed C# scripts reference is actually a wrapper linking to a corresponding piece of data in unmanaged code. When Unity decides to delete that backing object, it can do so with impunity. It then sets the managed GameObject into a special state where it compares as equal to null but is not actually null (generating MissingReferenceExceptions when you try to use it), until all references to it are cleared/go out of scope as per usual \$\endgroup\$ – DMGregory Mar 26 '17 at 16:04
1
\$\begingroup\$

Destroy() does not have an immediate affect on a GameObject. As m.rogalski points out, Destroy() ensures that the GameObject is destroyed safely. There are a couple of ways around this. If we want the GameObject to be immediately invisible to the game, we can use SetActive(). If we really need to, we can use DestroyImmediate(), though usage is unadvised.

Making the GameObject invisible as we Destroy() it

If you want the GameObject to be immediately invisible to the player, when you call Destroy(), you should also call SetActive(false). This will deactivate the GameObject, and remove it from play, while letting it idle in the background until it's Destroy() method completes.

public class DestroyScript : MonoBehaviour 
{
    public GameObject player;

    void OnTriggerEnter(Collision otherObj)
    {
        if (otherObj.gameObject.tag == "Player")
        {
            player.SetActive(false);
            Destroy(player);
        }
    }
}

Using DestroyImmediate()

If you just want to immediately Destroy() a GameObject, call DestroyImmediate(), instead. Be advised: DestroyImmediate() is extremely unsafe. It is advised that this method is used sparingly, and only for editor tasks; I typically use an #if UNITY_EDITOR to ensure that an actual build still uses Destroy(), instead.

public class DestroyScript : MonoBehaviour 
{
    public GameObject player;

    void OnTriggerEnter(Collision otherObj)
    {
        if (otherObj.gameObject.tag == "Player")
        {
            #if UNITY_EDITOR
            DestroyImmediate(player);
            #else
            Destroy(player);
            #endif
        }
    }
}

It is very important to note the overload for DestroyImmediate(); while you provide an Object, much like Destroy(), you can also provide a bool to permit asset deletion. This bool defaults to false, but it is important to know that the functionality there can permanently delete assets.

public class DestroyScript : MonoBehaviour 
{
    public GameObject player;

    void OnTriggerEnter(Collision otherObj)
    {
        if (otherObj.gameObject.tag == "Player")
        {
            // I am now permitting permanent asset deletion. 
            // This can be real bad, mmkay?
            #if UNITY_EDITOR
            DestroyImmediate(player, true);
            #else
            Destroy(player);
            #endif
        }
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ Is there any source on why the DestroyImmediate is unsafe? I mean I'll take your word for it and just try not to use it but it'd be nice to know why it's unsafe too. \$\endgroup\$ – John Hamilton Feb 9 '17 at 10:58
  • 1
    \$\begingroup\$ @John Hamilton, only speculation, but I believe it circumnavigates cleanup (it was mentioned that Destroy() is slower as it makes sure each component is destroyed, too). There is also the fact that you can permanently delete assets. If you send in a reference to a game object in your assets (I.e. a prefab), and set the Boolean flag to true, it will delete the prefab. It also states that it is unsafe in the official documentation I linked. \$\endgroup\$ – Gnemlock Feb 9 '17 at 11:16
  • \$\begingroup\$ This issue looks a bit funny to me. Even though Destroy does defer actual destruction, the docs say it waits only until the end of a given frame's updates, before rendering for that frame. I've never observed a lag like the one described in the question, so I wonder whether there might be something else going on here - say one of a dozen common errors in setting up physics so the collision isn't detected & OnTriggerEnter called until later than expected. \$\endgroup\$ – DMGregory Mar 26 '17 at 16:17
  • \$\begingroup\$ @DMGregory, all I could put it down to was user configuration error, but it does seem odd. \$\endgroup\$ – Gnemlock Mar 26 '17 at 18:15
  • \$\begingroup\$ this solution works for me! thanks so much!!! \$\endgroup\$ – Tina Lee Aug 20 '20 at 11:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.