stee_vo
stee_vo

Reputation: 33

How do I make the program do something when an object is destroyed?

I have plane(as in air plane) objects in my program, they get destroyed when bullets hit them but they also get destroyed after 5 seconds, when they exit the screen.

I also have a health script that resets the whole thing when it goes down to 0, and I want to remove a point every time the object is destroyed, but only when off screen. So I keep the scripts separate.

I use this in the ships spawn script to destroy them after 5 seconds, simple enough.

Destroy(spawnedPlane, 5f);

It would be perfect if I could just have some code that does "Destroy this object after X seconds AND add this to this value". Because as I understand it, "destroy" only accepts 2 parameters and nothing else.

Surely it is possible but I am at a loss. Still very new to this. Sorry if this is very unclear but I barely know what I'm doing myself.

Upvotes: 1

Views: 1719

Answers (3)

Technoguyfication
Technoguyfication

Reputation: 1304

Just use a coroutine to wait and then subtract a point and destroy the object at the same time.

void Start()
{
    // your startup script
    StartCoroutine(DestroyAfterSeconds(5f));
}

IEnumerator DestroyAfterSeconds(float seconds)
{
    // wait for X amount of seconds before continuing on
    yield return new WaitForSeconds(seconds);

    /*
     *  this runs after the wait.
     *  if the coroutine is on the same gameobject that you are
     *  destroying, it will stop after you run Destroy(), so subtract
     *  the point first.
     * */
    points--;
    Destroy(spawnedPlane);
}

Upvotes: 2

Jack Mariani
Jack Mariani

Reputation: 2408

If it was me I would surely go with events as suggested by CaTs.
Coroutine are another way to do that, but events are better in general at least in this case. Also using a Coroutine for just one Invoke is a bit an overkill (and unity Coroutines are a bit not performant.) Also the coroutine must be outside of the object you want to destroy because Unity Coroutines die when their MonoBehaviour is destroyed.

If you are still uncomfortable with events you...
well you should overcome it and try them anyway.

You could take a shortcut you can use More Effective Coroutine - Free.

And launch this code:

Timing.CallDelayed(5f, DestroyAndRemoveHP());

Basically this will run your logic with the delay you want to apply.
DestroyAndRemoveHP will be your method to destroy the platform and do anything else you like.

Full method description.

On the plus side you will start using MEC that are better than unity coroutine, but learning events makes you also a better programmer. You might do both.

Upvotes: 1

CaTs
CaTs

Reputation: 1323

You can use events to cleanly achieve what you are after. Below is an example of an event you might find useful. Other objects can listen to the event and once it is triggered, they will be notified.

[Serializable]
public class PlaneEvent : UnityEvent<Plane> { }

Once you have defined your event, you can then add it as a field in your Plane. Once your plane has been destroyed, you can fire the event and it will in turn notify anyone who is listening!

public class Plane : MonoBehaviour {

    public PlaneEvent OnDestroyed;

    public void Destroy () {
        Destroy(gameObject);
        OnDestroyed.Invoke(this);
        OnDestroyed.RemoveAllListeners();
    }

}

Now in our score class, we add a method that will be called once the OnDestroyed plane event is triggered.

public class Score : MonoBehaviour { 

    public void AddPointsFor (Plane plane) {
        Debug.Log("A Plane was destroyed!");
        //Tick a counter, add points, do whatever you want!
    }

}

Once we have these pieces, it is trivial to make them work together. We take the plane and we add the score as a listener to the OnDestroyed event. Then once the plane is destroyed, the event is fired and score is told to add points.

public class Game : MonoBehaviour {

    [SerializeField]
    private Score _score;
    [SerializeField]
    private Plane _plane;

    public void Start () {
        // When you are destroyed let me know so I can add some points.
        _plane.OnDestroyed.AddListener(_score.AddPointsFor);
        _plane.Destroy();
    } 
}

Another big advantage in using events is your plane has no idea that a score even exists, it will let anyone who cares know that it has been destroyed. In the same way this event could also be used to trigger particle effects, animations and sound effects when the plane is destroyed and all you need to do is add more listeners.

Upvotes: 5

Related Questions