23
\$\begingroup\$

I have an enemy with this structure:

  • Enemy
    • Body
      • Head
      • Arm Left
      • Arm right

...and so on. I also have a collider for each part of the body.

In my "Enemy" object I've attached a script, and in that script I would like to intercept possible collisions (from a bullet) hitting the body, head, arm, left etc.

How can I to do this?

\$\endgroup\$
0

5 Answers 5

29
\$\begingroup\$

If you're using a Rigidbody with the character, you can get this out of the box. :)

So your hierarchy could look like this:

  • Character (has Rigidbody and control script)
    • child (maybe has colliders)
      • grandchild (maybe has colliders)

OnCollisionEnter messages will fire on the GameObject containing the Rigidbody, reaching your parent control script without needing to write an extra relay script to stick on each collider.

If you need to find out which of your child colliders was involved in the collision, you can do it like so:

void OnCollisionEnter(Collision collision) {
    Collider myCollider = collision.GetContact(0).thisCollider;
    // Now do whatever you need with myCollider.
    // (If multiple colliders were involved in the collision, 
    // you can find them all by iterating through the contacts)
}
\$\endgroup\$
10
\$\begingroup\$

One way to solve this would be to have two scripts: one for the Enemy object and another one for the child(that you need to assign to the children of the Enemy obj)

Parent script

using UnityEngine;

 public class ParentScript : MonoBehaviour 
 {
     public void CollisionDetected(ChildScript childScript)
     {
         Debug.Log("child collided");
     } 
 }

Child script

using UnityEngine;

public class ChildScript : MonoBehaviour 
{
     void OnCollisionEnter(Collision collision)
     {
         transform.parent.GetComponent<ParentScript>().CollisionDetected(this);
     }
 }

This way you should get notified whenever a collision occurs to a child

\$\endgroup\$
1
  • 5
    \$\begingroup\$ If you use a solution like this and these collision happen a lot, I highly recommend having the children cache their receiving parent's GameObject. It's a good habit any time you're going to be calling the same GetComponent a lot and allows you to make any of the trickier "finding which parent up the chain to send to" logic only need to happen once. Also remember that transform.parent will only get the immediate parent. \$\endgroup\$
    – Lunin
    Dec 3, 2017 at 19:25
3
\$\begingroup\$

Direct quote from Unity Answers (written by Ashish Dwivedi):

Add a script to child and inside it have a reference of script of parent object. Now write 3 methods in parent script like ( OnCollisionEnter2DChild , OnCollisionStay2DChild , OnCollisionExit2DChild ) and called respective method from the methods (OnCollisionEnter2D , OnCollisionStay2D , OnCollisionExit2D) which are in child object script by passing the collision object.

\$\endgroup\$
1
  • \$\begingroup\$ I agree with this. The accepted answer of relying on components passing the collision up did not work for me. I actually used OnTrigger functions if anyone came here looking for that. It's the same principal. \$\endgroup\$
    – Joe Essey
    Dec 14, 2020 at 17:19
2
\$\begingroup\$

You can simply pass the top object to the children and call a function directly on it. This guarantees that you don't have to rely on parent propagation. So you don't end up doing silly things like transform.parent.parent

You could however automate this process with GetComponentInParent. This retrieves the first script it finds. Then cache that in your collision object, directly call functions on said cached object.

Alternatively you could make use of UnityEvents ( don't use Messages ) to bind functions to the child object. With unity events you can add any arbitrary listener so you can do more than just notify the top level object of the child object being hit.

\$\endgroup\$
1
\$\begingroup\$

You can perform a check on the collision and see which hit box was hit and also get the point of impact if needed.

note: the rigidbody is placed on the same object that has the Collision Check script.

This example is checking to see which hitbox the 'projectile' hit on a target.

private void OnCollisionEnter(Collision collision)
{                 
    if (collision.contacts[0].otherCollider.transform.gameObject.name == "HeadShot")                
       //DO STUFF            

    if (collision.contacts[0].otherCollider.transform.gameObject.name == "BodyShot")
       //DO STUFF    
}
\$\endgroup\$

You must log in to answer this question.

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