Applying explosion force to destructible object AFTER it's been destroyed

Hi there,

I have an FPS game with a rocket launcher, and a crate which is destructible.

Basically, when the rocket collides with anything, it spawns an explosion object, which has this script to apply explosive force to any object in range:

public class Explosion : MonoBehaviour
{
    public float explosionRadius = 10f;
    public float explosionUpwardsForce = 1f;
    public int explosionDamage = 100;
    public float explosionForce = 70f;
    public float explosionDamageFalloff = 1f;

    private IEnumerator Start()
    {
        // wait one frame before starting, to ensure all objects are affected
        yield return null;
        var rigidbodies = new List<Rigidbody>();
        Collider[] objectsInRange = Physics.OverlapSphere(transform.position, explosionRadius);

        // for every object within the explosion radius with a rididbody component, add them to the rigidbody list
        foreach (Collider collision in objectsInRange)
        {
            if (collision.attachedRigidbody != null && !rigidbodies.Contains(collision.attachedRigidbody))
            {
                rigidbodies.Add(collision.attachedRigidbody);
            }

            // if any object has a target script attached, run the take damage function, with a fall-off effect, i.e. the further away the target is from the explosion origin, the less damage they take
            Target target = collision.GetComponent<Target>();
            if (target != null)
            {
                float proximity = (transform.position - target.transform.position).magnitude;
                float effect = explosionDamageFalloff - (proximity / explosionRadius);
                // if the target is very close to the explosion origin, take full damage
                if (proximity <= 0.7f)
                {
                    target.takeDamage(explosionDamage);
                }
                // else, take splash damage
                else
                {
                    target.takeDamage(explosionDamage * effect);
                }
            }
        }
        // wait one frame before starting, to ensure all objects are affected
        yield return null;
   
        // add explosion force to each rigidbody
        foreach (var rb in rigidbodies)
        {
            rb.AddExplosionForce(explosionForce, transform.position, explosionRadius, explosionUpwardsForce, ForceMode.Impulse);
        }
    }
}

And when the crate is destroyed, it spawns a destroyed version which is made up of lots of small pieces of the crate, all of which have rigidbodies. This is the script for the crate:

public class Destructible : MonoBehaviour
{
    public GameObject destroyedVersion;	// Reference to the shattered version of the object
	 
	void OnDestroy ()
	{
		// When the object is destroyed, spawn a shattered object
		Instantiate(destroyedVersion, transform.position, transform.rotation);
	}
}

So at the moment the explosion does not affect the crate after it’s been destroyed, the pieces just fall to the ground. I’m not sure how to make it so that the explosion affects them too?

I’ve tried adding a small delay to the explosion script before applying force but that doesn’t work because the pieces are not in the collider array.

Any help appricated! Thanks :slight_smile:

Well, what you essentially need is to perform another Physics.OverlapSphere after you applied your damage. Since after applying the damage there might be new rigidbodies.

IEnumerator Start()
{
    yield return null;
    Collider[] objectsInRange = Physics.OverlapSphere(transform.position, explosionRadius);
    
    foreach(var collider in objectsInRange)
    {
        Target target = collider.GetComponent<Target>();
        if (target != null)
        {
            // your damage code
        }
    }
    yield return null;
    
    var rigidbodies = new HashSet<Rigidbody>();
    objectsInRange = Physics.OverlapSphere(transform.position, explosionRadius);
    foreach (Collider collider in objectsInRange)
    {
        var rb = collider.attachedRigidbody;
        if (rb != null && rigidbodies.Add(rb))
        {
            rb.AddExplosionForce(explosionForce, transform.position, explosionRadius, explosionUpwardsForce, ForceMode.Impulse);
        }
    }
}

HashSet.Add will return “true” if the object is not yet in the set and returns false if it is already in the set.

In your script void OnDestroy, it instantiates the destroyedVersion.

Use that script to give the destroyedVersion the same force (or same velocity), perhaps with some multiplier, that was given to the original object.

 public class Destructible : MonoBehaviour
 {
     public GameObject destroyedVersion;    // Reference to the shattered version of the object
      
     void OnDestroy ()
     {
         // When the object is destroyed, spawn a shattered object
         GameObject pieces = Instantiate(destroyedVersion, transform.position, transform.rotation);
         float someMultiplier = 3f; // the small pieces maybe move faster than the whole, right?
         pieces.GetComponent<Rigidbody>().velocity = someMultiplier*GetComponent<Rigidbody>().velocity;
     }
 }

This assumes that both the original and the destroyedVersion are of the type Rigidbody.

Tweak this and you should get a working model up.