7
\$\begingroup\$

I have two Collision Boxes on the same GameObject. I don't want the Collision Boxes to be triggers. I want the Collision Boxes on the actual GameObject, not its children.

For example, if I want to check for a headshot. My reason for not wanting triggers is that a trigger is already being used. My reason for not wanting children is for cleanliness. I understand there are work arounds. I was wondering if there was a more direct approach.

When there is a collision, how can I check which Collision Box is hit?

\$\endgroup\$
  • \$\begingroup\$ Have u checked collision by print? U simply can print something in OnCollisionEnter block... \$\endgroup\$ – Shraddha Patel Dec 7 '15 at 4:54
  • \$\begingroup\$ Hello. Can I know why do you need to know what Collision Box is hit? \$\endgroup\$ – xitnesscomplex Dec 7 '15 at 6:00
  • \$\begingroup\$ You don't necessarily need multiple colliders. Depending on what your requirements are, the task can be accomplished with a single collider. Can you provide some more details? \$\endgroup\$ – SanSolo Dec 7 '15 at 6:02
  • \$\begingroup\$ For example, if I want to check for a headshot. My reason for not wanting triggers is that a trigger is already being used. My reason for not wanting children is for cleanliness. I understand there are work arounds. I was wondering if there was a more direct approach. \$\endgroup\$ – Evorlor Dec 7 '15 at 6:09
  • \$\begingroup\$ I don't think there is a direct approach. I'm thinking of getting Distance as a work around. \$\endgroup\$ – xitnesscomplex Dec 7 '15 at 6:47
1
\$\begingroup\$

If you want to just have one GameObject for your character, you cannot add multiple Colliders of the same type to your GameObject and still have the ability to access all of them in your scripts (only the first in order of components would be accessible). However, you CAN add multiple Colliders of DIFFERENT types while still maintaining accessibility. In your case you could add CapsuleCollider or BoxCollider for the body and a SphereCollider for the head. The script for accessing these Colliders would go as follows:

using UnityEngine;
using System.Collections;

public class BulletScript : MonoBehaviour {

CapsuleCollider bodyCollider; //OR BoxCollider bodyCollider;
SphereCollider headCollider;

void Start () 
{
    bodyCollider = desiredGameObject.GetComponent<CapsuleCollider> (); //OR bodyCollider = gameObject.GetComponent<BoxCollider> ();
    headCollider = desiredGameObject.GetComponent<SphereCollider> ();
}

void OnTriggerEnter (Collider other)
{
    if (other == bodyCollider)
    {
        //This happens when the body is hit
    }
    if (other == headCollider)
    {
        //This happens when the head is hit
    }
}

This script would be attached to your bullet (make sure to add a Trigger Collider as well). The OnTriggerEnter method would check if any Collider has entered the bullet's Trigger Collider. The if statements check which Collider has entered the Trigger Collider. Problem Solved.

Let me know if you have any questions or suggestions.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

I know of a way to do this, if you created your colliders programatically. See the following source code:

using UnityEngine;
using System.Collections.Generic;

public class MultipleColliders : MonoBehaviour {

    //Enumeration to tell us what a collider is for
    enum ColliderType
    {
        Head,
        Body
    }

    //A quick lookup for our colliders associated with this gameobject
    Dictionary<Collider2D, ColliderType> Colliders;

    void Start () {
        InitColliders ();
    }

    //Programmatically create our colliders
    void InitColliders()
    {       
        Colliders = new Dictionary<Collider2D, ColliderType> ();

        BoxCollider2D boxCollider = transform.gameObject.AddComponent (typeof(BoxCollider2D)) as BoxCollider2D;
        boxCollider.offset = new Vector2 (0, -0.5f);
        boxCollider.size = new Vector3 (0.5f, 1f);
        Colliders.Add (boxCollider, ColliderType.Body);

        CircleCollider2D circleCollider = transform.gameObject.AddComponent (typeof(CircleCollider2D)) as CircleCollider2D;
        circleCollider.offset = new Vector2 (0, 0.5f);
        circleCollider.radius = 0.5f;
        Colliders.Add (circleCollider, ColliderType.Head);
    }

    //Check if our colliders were hit
    void Update () {

        //Raycast mouse cursor when pressed to simulate a hit for our example
        if (Input.GetMouseButtonDown (0)) {

            Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);            
            RaycastHit2D[] hit = Physics2D.RaycastAll (mousePosition, Vector2.zero);

            //lookup our hits to see what was hit
            for (int i = 0; i < hit.Length; i++)
            {
                if (Colliders.ContainsKey(hit[i].collider)) {
                    Debug.Log ( System.Enum.GetName( typeof(ColliderType), Colliders[hit[i].collider]) + " HIT!");              
                }
            }           
        }       
    }
}

So basically, doing it this way, will provide you with the requirements you supplied. It will allow a gameobject to contain multiple colliders without having to be each a child object.

It will also be able to tell you what collider was hit.

Let me know if you have questions about this implementation.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks, but adding the Colliders programmatically will not work for me. \$\endgroup\$ – Evorlor Dec 7 '15 at 13:13
  • 3
    \$\begingroup\$ In that case, you should use child objects. Otherwise, it will be very difficult to differentiate each collider from each other. Another option, could be to extend the collider class and create your own, in which you can add a new property to distinguish the collider. \$\endgroup\$ – jgallant Dec 7 '15 at 13:22
  • \$\begingroup\$ Hmmm...I never thought about extending the Collider Component. Is that possible? I like it. \$\endgroup\$ – Evorlor Dec 7 '15 at 13:25
  • 2
    \$\begingroup\$ Yes, however, this is not easy, as you will need to extend from Collider2D, and not any pre-defined colliders. I haven't personally done this before, but from what I can gather, this is not a simple task. \$\endgroup\$ – jgallant Dec 7 '15 at 13:28
0
\$\begingroup\$

I'd recommend making an empty game object that parents both game objects for the enemy as a whole, and a second one for the head. Then you could write a check based on the bullet intersecting with the head and go from there.

using UnityEngine;
using System.Collections;

public Class BulletScript : MonoBehaviour {

public Transform bullet;
//tag as "Bullet"

void Start(){
  bullet = transform;
}

void OnTriggerEnter (Collider other){
   if (other.gameObject.CompareTag("Head"){
     Debug.Log("Headshot.");
   }

   if (other.gameObject.CompareTag("Enemy"){
      Debug.Log("Not a head shot.");
   }
 }
}
| improve this answer | |
\$\endgroup\$
-1
\$\begingroup\$

After some research, I've found an easy way to do this without any workarounds.

When creating Colliders, use different names in each of them, as head, torso, legs, arms. Then on OnCollisionEnter method, you just had to check all of the contact points.

void OnCollisionEnter(Collision col)
{
    foreach (ContactPoint contact in col.contacts)
    {
        Debug.Log(contact.thisCollider.name + " hit " + contact.otherCollider.name);

        if (contact.thisCollider.name == "HitBoxHead") {
            Debug.Log("Head Shot");
        }
    }
}
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.