onCollisionEnter does not work on a child colider

I want to put a script with an OnCollisionEnter function on a child object of another object that has a rigid body on it, but when the script is on the child object it doesn’t register.

To say it another way, I have two cubes, one cube is the child of the other cube and the root cube has a rigid body on it. OnCollisionEnter works on the root rigid body cube, but that same function put on the child cube, which is not rigid body and just has a collider, the onCollisionEnter function stops working.

Now it works when the root cube is not a rigid body. If both cubes just have colliders, the oncollisionenter works on the child colliders. But if the root object has a rigidbody, it seems to disable the OnCollisionEnter function for all it’s children.

Is this just how the Unity engine is? Or am I doing something wrong? How do I get the onCollisionEnter function to register on a child object or rigidbody?

Or do I need to do some workaround to only have such a function on the root cube?

2 Likes

This is actually the correct behaviour. You need to have the script and the rigidbody on the parent object.

2 Likes

Is there some way to sense if it is colliding with a child collider of the rigid body?

The child colliders don’t register collisions with each other. This allows you to make combinations of colliders to model irregular shapes. Are your child colliders supposed to be free-moving relative to the parent?

1 Like

No they aren’t free moving, I just need to know when it collides with one of the children.

If you have the OnCollisionEnter on the parent, then collisions with any of the children will also be detected.

1 Like

Is it possible to detect the collision at the child object rather than at the parent object? For example, if I want to detect a head shot.

1 Like

The Collision object passed to OnCollisionEnter has a field representing the collider that was hit. If you have references to all your object’s colliders (say with public variables) you can compare them with the collider in the Collision object:-

var headColl: Collider;
var bodyColl: Collider;
// etc...

function OnCollisionEnter(coll: Collision) {
    if (coll == headColl) {
        // Do the head shot thing
    }
}
2 Likes

I think I’m having the same problem and I think that this answer, while true, isn’t correct for what we’re looking for. Or maybe it was and my issue is different… either way…

I have a parent object with a rigidbody and a script.
Then I have a group of colliders as children of that. When OnCollisionEnter is called on the parent, coll will equal the collider of the other object that I hit. How can I get a reference to which child collider on the object running the script was hit?

I figured it out. If anybody’s interested:

foreach (ContactPoint c in collision.contacts)
        {
            Debug.Log(c.thisCollider.name);
        }
15 Likes

Hei great! that helped me a lot!

Many thanks for your post :slight_smile:

I can’t get it to work.

var headColl: Collider;
var bodyColl: Collider;
// etc...

function OnCollisionEnter(coll: Collision) {
    if (coll == headColl) {
        if(coll.gameObject.name == "Blast(Clone)") 
		{ 
			//SendMessageUpwards("Destroy");
			Destroy(gameObject);
		}
    }
	if (coll == bodyColl) {
        Destroy(gameObject);
    }
}

I have a human model which is the parent and has this script. And a simple capsule with capsule collider added as a child. It’s a bit away from the model so you can hit it easily. For the variable I selected the name of that capsule object. But when you shoot it, or hit it nothing happens.

What am I doing wrong?

I know this is an old thread, but I ran into the same problem recently.

andeee’s advice is not quite right, but eekllc is.

The gameObject, collider, and rigidbody in the Collision parameter all refer to the topmost object involved in the collision. To determine which sub-collider was hit, you need to look at the contact points’s thisCollider or otherCollider depending on whether you’re calling OnCollisionEnter on the target or the projectile.

1 Like

Ok, but what if I’m using a trigger and not a collision?

Is there a way to get the collision contacts from the collider in OnTriggerEnter?

OnTriggerEnter doesn’t give contact point info, only Collisions do.

1 Like

Hello,

I have one parent gameobject with a rigidbody and 100 child block objects with each a box colliders on it. My other object is a simple sphere which can bounce against the block structure. The sphere contains a rigidbody with sphere collider. The OnCollisionEnter Function from the sphere is reporting due reading the contact normals othercollider object often itself back instead of 1 of the 100 child blocks. With other words: othercollider is for my setup not reliable. Is there some more reliable way that tells me which block was hit and only includes 1 rigidbody for my block structure setup.

Thanks,

Peter.
Unity Pro 4.3.2

I think that I found a suitable solution. Here comes the code snippet:

bool otherColliderFound;

	void OnCollisionEnter (Collision col)
	{
		otherColliderFound = false;

		if (col.gameObject.GetInstanceID () != gameObject.GetInstanceID ()) {
			otherColliderFound = true;
			ExecuteCollision (col);
		}
	}

	void OnCollisionStay (Collision col)
	{

		if (!otherColliderFound  col.gameObject.GetInstanceID () != gameObject.GetInstanceID ()) {
			ExecuteCollision (col);
		}
	}

void ExecuteCollision (Collision col)
	{
              //Do some collision stuff
	}

Peter.

The above example is useless if you wan’t to do some proper collision math with contact points in OnCollisionEnter. In my case it was possible to use a static batch without any rigidbody which provides accurate information about the contact points. Even here the othercollider object is not always populated. It seems a normal behaviour from Physics: http://gamedev.stackexchange.com/questions/40048/why-doesnt-unitys-oncollisionenter-give-me-surface-normals-and-whats-the-mos

If you need more information about the other object then Physics provides then cast a ray to it with something like this (incomplete snippet). Please also note that the surface normal is not the same as the collision normal due for example more objects that are mostly hit (wall, floor and so on):

void OnCollisionEnter (Collision col)
{
            m_breakOutPhysicsObjectTest = false;

			for (int i = 0; i < col.contacts.Length; i++) {

				if (Physics.Raycast (m_transform.position, (col.contacts[i].point - m_transform.position).normalized, out m_collisionhit, 5f, m_onCollisionRayLayerMask)) {
					m_contactPointNormal = m_collisionhit.normal;
					//Debug.DrawRay (m_transform.position, (col.contacts[i].point - m_transform.position).normalized, Color.red);
					//Debug.Log (m_collisionhit.transform.gameObject.name);
					//Debug.Break();
					m_breakOutPhysicsObjectTest = true;
				}

				//Debug.Log (m_breakOutPhysicsObjectTest);

				if (m_breakOutPhysicsObjectTest)
					break;
			}

Peter.

@eekllc How do I use this, do i put it in onCollisionEnter?

I too ran into this problem.

I had a rigidbody and a collider on a root object, and the same on one of it’s children. I also had OnCollisionStay in scripts both on the root and the child. I expected OnCollisionStay to be only called on the child’s script (when the child collider hit something) but it was called on both the child script AND the root. This was not the behaviour I wanted and searching through all collision contact points seemed a bit like overkill.

I found a much simpler solution. I created a new child, and moved the collider from the root object to this new child. I also moved the corresponding script containing OnCollisionStay to this new child.

By moving all colliders off the root object, they each call OnCollisionStay on their respective scripts separately. There is no longer a script with OnCollisionStay on my root rigidbody object and so I’m no longer getting the double call, and can determine exactly which collider and child object is triggering OnCollisionStay.