Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How To Respond to Child Object's Collisions

Discussion in 'Scripting' started by steviebob, Nov 13, 2014.

  1. steviebob

    steviebob

    Joined:
    Jul 15, 2014
    Posts:
    21
    Hello,
    I have a character model, which has colliders on it's limbs.
    I would like to attach a script to the parent (the character) and listen for any collisions of it's child objects (The limbs).

    I've tried this with a simple sphere with a capsule as a child, then had the OnCollisionEnter() event in a script attached to the sphere.
    Within this method, I'm using Collision.gameObject.name, but that only ever reports the thing that collided with the Sphere (The parent).

    Does anyone know how to get the name of both of the objects that are colliding?

    The easy way to understand what I'm asking is that I'm able to get both items that are colliding together, but this will require me to add a script to every limb within the character. I need to listen to all collisions of the character within a single script.
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    You actually can't AFAIK. Collision events always bubble up to the parent. It's sort of a bummer.
     
  3. steviebob

    steviebob

    Joined:
    Jul 15, 2014
    Posts:
    21
    Seriously?
    That's very surprising.
    So are you saying that I need to attach the same script to every limb that I want to listen to it's collisions for?
    I guess since I should only have to do it once, it's not a major concern, just a pain in the backside really.

    Is there no global "someStuffCollided()" method somewhere to capture all collisions? (Wishful thinking)
     
  4. IsGreen

    IsGreen

    Joined:
    Jan 17, 2014
    Posts:
    206
    You can join the meshes into one.

    The result(meshes joined) is not rendering. It is a mesh that only uses MeshCollider.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3.  
    4. [RequireComponent(typeof(MeshCollider)),
    5. RequireComponent(typeof(Rigidbody))]
    6. public class JoinMeshes : MonoBehaviour {
    7.  
    8.     public MeshFilter[] meshes;
    9.  
    10.     void Start () {
    11.  
    12.         //Only need vertices and triangles array
    13.         List<Vector3> vertices = new List<Vector3>();
    14.         List<int> triangles = new List<int>();
    15.  
    16.         int lastVertice = 0;
    17.         Vector3 center = this.transform.position;
    18.  
    19.         foreach(MeshFilter meshFilter in this.meshes){
    20.  
    21.             Matrix4x4 matrix = meshFilter.transform.localToWorldMatrix;
    22.             Mesh m = meshFilter.mesh;
    23.  
    24.             foreach(Vector3 v3 in m.vertices) vertices.Add(matrix.MultiplyPoint3x4(v3) - center);
    25.             foreach(int i in m.triangles) triangles.Add(i+lastVertice);
    26.  
    27.             lastVertice += m.vertices.Length;
    28.  
    29.         }
    30.  
    31.         Mesh joinMesh = new Mesh();
    32.         joinMesh.vertices = vertices.ToArray();
    33.         joinMesh.triangles = triangles.ToArray();
    34.  
    35.         GetComponent<MeshCollider>().sharedMesh = joinMesh;
    36.  
    37.     }
    38.  
    39. }
    Download link.
     

    Attached Files:

    Last edited: Nov 14, 2014
  5. steviebob

    steviebob

    Joined:
    Jul 15, 2014
    Posts:
    21
    I don't think that will work for my scenario (Unless I've misunderstood).
    I need the individual colliders to exist so I can detect which part of the body has been hit.
     
  6. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Also wouldn't work if the mesh was skinned/animated in any way.

    Basically, child colliders are treated as one big compound collider which is why they report collisions to their parent. Admittedly, it would be nice to get some info about what collider was hit.
     
    steviebob likes this.
  7. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,183
    The usual way to do this is to not have an OnCollisionEnter on the parent, only on the children. The children simply send the collision on to the parent object through a custom method where they also identify themselves.

    So you put something like this on the child script:

    Code (csharp):
    1. ParentScript parent;
    2. void Awake() {
    3.     parent = GetComponentInParent<ParentScript>();
    4. }
    5.  
    6. void OnCollisionEnter(Collision c) {
    7.     parent.RegisterCollision(this, c);
    8. }
    And in the parent script:

    Code (csharp):
    1. public ChildScript head;
    2. public ChildScript leftArm;
    3. // right arm, chest, etc.
    4.  
    5. public void RegisterCollision(ChildScript child, Collision c) {
    6.     if(child == head) {
    7.         DoHeadShot(c);
    8.     }
    9.     //etc
    10. }
    This gives you exactly the behaviour you're looking for. If you want your code to be more modular - or if you just want the parent script to be shorter - you can subclass the child script into different scripts for the different limbs, and do some of the hit logic there instead of in the parent.
     
    cygnusprojects, steviebob and image28 like this.
  8. steviebob

    steviebob

    Joined:
    Jul 15, 2014
    Posts:
    21
    Thanks Baste, that's much closer to what I was looking for.

    Before I saw your response I done something similar, by without using a parent script.
    • I put the same script on every limb (child) and implemented the onCollisionEnter method.
    • Within that method I used this.gameObject.name (Which would give me the name of the limb) and collision.gameObject.name (Which gives me the thing that collided with the limb).
    • I'd then pass this into a "stuffCollided()" method, where I would make a decision as to whether or not to perform an action based on what it collided with, and how I should respond based on the limb that was hit.
    So I wasn't too far off from your suggestion.
    I like how you're explicitly referencing the child's parent, so I'll be sure to modify what I've got to incorporate that.
    Thanks again.