Destroy GameObject after seconds

Hi!
I’m working on a shield boost and I have almost completed it. The only problem is I cannot destroy or make it disappear after 10 seconds. I have tried to set it as inactive (newShield .SetActive(false)) and destroy it.
I’d be happy if you can help. Thanks!

private void OnTriggerEnter2D(Collider2D collision)
    {
        StartCoroutine(ShieldTrigger());
        Destroy(gameObject);
    }

    IEnumerator ShieldTrigger()
    {
        Player player = GameObject.FindObjectOfType<Player>();
        GameObject newShield = Instantiate(shieldPrefab, player.transform.position, player.transform.rotation);
        newShied.transform.parent = player.transform;
        yield return new WaitForSeconds(10);
        Destroy(newShield.gameObject);   //This is where I'm struggling
    }

Hi @Kubilay,

If you look at your code example and consider what happens in sequence…

  1. OnTriggerEnter2D gets called upon a collision taking place
  2. You start a Coroutine, that codes starts to run
  3. Meanwhile, the next line of code in your OnTriggerEnter2D method executes, e.g the ‘Destroy’ method call, the point of the coroutine is to run code simultaneously etc.

At the end of the current frame, the object that this code is executing on gets destroyed, as such, your coroutine code disappears with it - this will be why you are not seeing your Destroy(newShield.gameObject) line of code behave in the way you would expect, the code never gets that far in it’s execution.

To test to see if what I’m saying is true, temporarily, comment out the Destroy method call in the OnCollisionEnter2D method and run your game. This feels as if its most likely on some form of “collectable” power-up etc, so you’d still see that on the screen but, your shield should disappear.

Also, assuming it does you should be able to simplify that method call to just Destroy(newShield).

Hope this helps :slight_smile:

Hi @Rob,

You were right, it happened as you said. After that, I have tried to change the code a bit so that I could destroy the “collectable object” and run the shield but I could not make it as I wanted. So, this is the solution I found.

 private void OnTriggerEnter2D(Collider2D collision)
    {
        StartCoroutine(ShieldTrigger());
    }

    IEnumerator ShieldTrigger()
    {
        GetComponent<Collider2D>().enabled = false;
        GetComponent<Renderer>().enabled = false;
        Player player = GameObject.FindObjectOfType<Player>();
        GameObject newShield = Instantiate(shieldPrefab, player.transform.position, player.transform.rotation, player.transform) as GameObject; //Sondaki player.transform parent
        yield return new WaitForSeconds(3);
        Destroy(newShield);
        Destroy(gameObject);
    }

I have tested it and works correctly.
I’d be happy if you share if there is a better way.

Thanks for the help!

Hi @Kubilay,

You’re welcome.

Looking at your approach, I’d probably aim to consider the separation of concerns. At the moment your “collectable” knows not only which power-up it is going to deliver, but it also wants to control that power-up’s behaviour.

I would probably start by creating a PlayerShield class/script, perhaps pop it in a “Power-Ups” folder.

This class would literally just handle the behaviour related to the shield itself, so, you could either move your coroutine code into it and then call it from the Start method, or, if you don’t need as much control over what happens when, e.g. you just want to destroy the shield GameObject after a period of time you could use Unity’s overloaded Destroy method;

// destroys the gameobject the script is attached to after 10 seconds
Destroy(gameObject, 10f);    

So, the PlayerShield script might look like this;

using UnityEngine;

public class PlayerShield : MonoBehaviour
{
    private void Start()
    {
        Destroy(gameObject, 10f);
    }
}

If you want more control over the behaviour, then stick with the coroutine approach and call that from the Start method;

using System.Collections;

using UnityEngine;

public class PlayerShield : MonoBehaviour
{
    private void Start()
    {
        StartCoroutine(SelfDestruct());
    }

    private IEnumerator SelfDestruct()
    {
        // do coroutine stuff in here
    }
}

In all cases you might want to consider a few thing like;

  • any audio sfx when the shield activates/de-activates
  • any particle effects to start/stop
  • a configurable/random duration for the power-up

The PlayerShield script would be attached to your shield prefab. When you instantiate it from the code in your “collectable”, it’s Start method will fire, as such you have now separated the behaviour of what the shield will do from the code in your “collectable”.

This will then allow you to just Destroy the “collectable” game object after instantiating the shield prefab.

The approach above would also allow you to extend your power-up functionality, your “collectable” could effectively randomise which power-up a player may get, you’d have a separate script for each power-up type, attached to the appropriate prefab. Your code above to instantiate would be largely the same, you’d just randomise a number, and then choose the appropriate prefab based on the value.

Hope the above is of use. :slight_smile:


See also;

1 Like

Hi @Rob,

Thanks for the help, I will try this method.

1 Like

You’re very welcome :slight_smile:


See also;

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms