1
\$\begingroup\$

Problem

I have a set of various objects on my map that I would like to make destructible. Basically, they are split into 3 parent objects - plants, buildings and moving objects. Each parent contains 100+ children. So, if I shoot an object or objects, it/they should suffer certain amount of damage, and if the damage is critical then get destroyed.

So, I have created a single script called Damageable and added it to every child described in the previous paragraph as below:

Damageable.cs

public class Damageable : MonoBehaviour
{
    private float m_CurrentHealth;  
    private bool m_Destroyed;     
    ...

    public void TakeDamage(float amount)
    {
        m_CurrentHealth -= amount;

        if (!m_Destroyed && m_CurrentHealth <= 0f)
        {
           HandleDeath();
        }
    }

    ...

}

Then, in my ShellHit script, I retrieve a list of affected Damageable objects and cause them damage via TakeDamage method.

ShellHit.cs

public class ShellHit : MonoBehaviour 
{
    ...
    private void OnTriggerEnter(Collider other)
    {
        Collider[] colliders = Physics.OverlapSphere(transform.position, m_ExplosionRadius, m_DamageableMask);

        foreach (Collider collider in colliders)
        {
            Rigidbody targetRigidBody = collider.GetComponent<Rigidbody>();

            targetRigidBody = collider.GetComponent<Rigidbody>();
            if (!targetRigidBody)
            {
                continue;
            }

            targetRigidBody.AddExplosionForce(m_ExplosionForce, transform.position, m_ExplosionRadius);

            Damageable damageable = targetRigidBody.GetComponent<Damageable>();

            if (!damageable)
            {
                continue;
            }

            float damage = CalculateDamage(targetRigidBody.position);

            damageable.TakeDamage(damage);
            
            ...
        }
    }
    ...
}

Question

Is it a common practice in Unity what I'm doing by adding the same script to every game object or is there a more common/efficient way of doing the same? For instance, by adding the script to a parent object and make it handle the damage for its children.

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

There are several ways to accomplish this, I suggest you look into using tags with your colliders. Here is the documentation for the Unity Tag System : https://docs.unity3d.com/2019.3/Documentation/Manual/Tags.html

You can differentiate colliders by tag with something like :

 private void OnTriggerEnter(Collider other)
{
   if(other.gameObject.tag == "damagable")
    { //do damage stuff here }   
}

This way you don't have to do an expensive call to search for the objects rigid body.

You could also look into other ways to improve performance when dealing with a large number of game objects. I suggest researching Unity Addressables and Object Pooling.

\$\endgroup\$
3
  • \$\begingroup\$ If you're going to compare tags, favour using .CompareTag() over .tag == for efficiency. But I'd recommend physics layers over tags at all. With physics layers, you can filter your collisions/triggers before the callback even gets called, rather than going to all the work of finding the collision handlers and calling them only to result in a no-op. \$\endgroup\$
    – DMGregory
    Dec 7, 2020 at 17:49
  • \$\begingroup\$ Good advice, I agree .CompareTag() is probably better. I honestly haven't used the collision system lately. Since you have more suggestions you should post an answer :) \$\endgroup\$
    – NCarlson
    Dec 7, 2020 at 18:14
  • \$\begingroup\$ Thanks for your reply! Actually I'm using a tag for damageable objects already - Physics.OverlapSphere(transform.position, m_ExplosionRadius, m_DamageableMask);. m_DamageableMask is the tag. But what is not clear is if it's a good practice in Unity to add the same script to every child that should be damageable. \$\endgroup\$
    – Anatolii
    Dec 8, 2020 at 4:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .