- Home /
Detecting which Collider involved in Trigger 'Collision'
My issue is mainly down to this: OnCollisionEnter() returns a Collision. OnTriggerEnter() returns a Collider.
With the former, I have been able to detect a Collider (bullet) hitting my rigidbody collection of colliders (player). Using Collision.contacts is the only way I've been able to discern which collider in my Player object has taken the hit, which is important for damage allocation.
However, in the case of what I shall call AlternativeBullet, I am using a trigger rather than a collider (because I don't want the collision to have a physics knockback). All I've got when a trigger touches part of the Player is the collider (ie. Trigger) that touched, not any actual location data such as Collision gives.
This is deceptively simple-looking. I originally expected the script calling OnCollisionEnter() or whatever to only be called on the object who's collider is being hit, but this is not the case. It is called on the object with the rigidbody, ie. the master Player object to which these GameObjects with colliders are parented. Hence the need to use Collision.contacts to find which collider actually got hit.
Can anyone suggest any alternative ways of finding which collider was 'hit' by the trigger version of the bullet. Or, better yet, a way of nullifying a collision the physics engine has already registered so the bullet won't have any momentum effect.
Thanks!
Well this is really silly, all answers here are really usefull and I'd vote them all up but I'd be casting myself down. So how about this, I vote up the people I think gave a good answer, ignore the bounty and you tell us what solution worked for you so the Q&A is usefull for everyone ? Good question btw
Answer by Statement · Dec 10, 2010 at 05:29 PM
You could get slightly better bullet code by doing a RayCast or a SphereCast every update, from the previous location to the current location of the bullet. Think of the sphere cast like a thick ray cast. Casting a ray or a sphere from one point to another reduce odd physics behaviour like tunneling and is probably easier to fix than your current situation.
You can then obtain an exact or approximate position where the ray or sphere hit the object.
You then don't need any collider at all on your bullet prefab.
You can send a custom message on bullet hit such as this psuedo code (just after the ray test):
if (hitOther)
{
other.SendMessage("OnBulletHit", bulletHit,
SendMessageOptions.DontRequireReciever);
}
And your player/enemy could have a function that handle this gracefully such as:
function OnBulletHit(bulletHit : BulletHit) { health -= bulletHit.damage; BloodEffects(bulletHit.position); PlayHitSound(bulletHit.position);
if (bulletHit.isRadioactive)
{
AddRadiationSickness();
}
if (health <= 0 && bulletHit.damage > 25)
{
ExplodeIntoGibParts();
}
}
You'd have to design your BulletHit structure or class yourself but that shouldn't pose any problems. You need to consider what data is important describing a bullet hit event and put that in your type.
- Note that there is a bug (unless they fixed that) where the SphereCast doesn't register hits with a Trigger. So if you need to be able to hit triggers with your bullets you should probably use RayCast instead.
Yes, I think so. I think it applies to those "volume" casts that were introduced. It's a shame really, they would be so useful.
I couldn't agree more! I was jumping through the roof when I saw capsulecast. Looked like something I wish I had a year ago. And then after a lot of "trying to figure out how to use it" I got strange results and kept trying. Still doing that...
Excellent suggestion; and I did consider raycasting a little after writing this question. But wouldn't RaycastHit return a collider in much the same way as OnCollision? I suppose being more like OnTrigger means it might return the right one. I shall experiment and let you know what fixes it, thanks!
Yes it does return the collider it hit, but it also gives the point of collision. Raycasts wouldn't do much use if you couldn't deduce where the ray hit something. It is useful for pushing the object exactly where you hit it, if you are dealing with physics for example.
Answer by Facundo · Dec 10, 2010 at 04:31 PM
OnTriggerEnter seems to return the right collider (actual descendant hit) in a test project I did: https://www.yousendit.com/download/cEd0K2VucVhsUi92Wmc9PQ
May I be overlooking something important in your specification?
Yeah I thought so aswell. I never had a problem with getting colliders. A collision can not really occur without 2 objects being registered any way you look at it. So even if you can just "handle" one you just read the other.
Curiously, OnTriggerEnter() does indeed, yes. However, if you switch from Trigger to Collider and modify the function accordingly, you should find it now only registers the root collider (just tried with that project you kindly supplied). This is what caused me to move the code onto the root object rather than the bullet, hence this current rather strange situation!
Answer by Proclyon · Dec 11, 2010 at 04:44 PM
You can prevent the rigidbody problem by destroying the rigidbody using a character controller in the physics section instead and use the OnControllerColliderHit function.
void OnControllerColliderHit(ControllerColliderHit cch)
{
Debug.Log("cch hit");
}
Doing this detects the start of a collision using the regular physics but the energy (kinetic) will not be transfered from object A to B. However the collision occurs is registered and a property of cch.collider DOES exist and can be retrieved giving you the collider you need without getting punched in the chest by some force
P.S.
I just tested this in a new project I whipped up for the question. It worked without a problem. Let me know if you get any results that differ. I can't promise I didn't forget something stupid (Humans tend to do that :/)
This is an intriguing workaround, but unbeknownst to ye, the object in question is an airship capable of rolls and turns, so I fear swapping the rigidbody for a character controller wouldn't be feasible. However, if you can link me to the example, I'd be interested to check it out.
Answer by lucianv · Oct 20, 2016 at 10:25 AM
To see which sub-collider hit the trigger object you might use the following method:
Create a simple script to use on each sub collider called ColliderProxy
using UnityEngine;
using System.Collections;
public class ColliderProxy : MonoBehaviour
{
public enum ColliderId { None, Body, Range };
public ColliderId colliderId = ColliderId.None;
public delegate void ColliderDelegate(ColliderId collider);
public event ColliderDelegate OnTriggerEnterByCollider;
void OnTriggerEnter(Collider other)
{
if (OnTriggerEnterByCollider != null)
{
OnTriggerEnterByCollider(colliderId);
}
}
}
On the main object you'll have something like this:
using UnityEngine;
using System.Collections;
public class MainObjectScript : MonoBehaviour
{
public GameObject objectWithSubcollider1;
public GameObject objectWithSubcollider2;
void Awake()
{
objectWithSubcollider1.GetComponent<ColliderProxy>().OnTriggerEnterByCollider += OnTriggerEnterByCollider;
objectWithSubcollider2.GetComponent<ColliderProxy>().OnTriggerEnterByCollider += OnTriggerEnterByCollider;
}
void OnTriggerEnterByCollider(ColliderProxy.ColliderId colliderId)
{
Debug.Log(“OnTriggerEnter by collider: " + colliderId);
}
}
Just set the ids for the subcolliders after attaching the script. On the scene object holding the trigger collider you'll need to have a rigidbody. On the subobjects holding the subcolliders you'll have just the colliders, if the main object doesn't have a rigidbody. If the main object has a rigidbody, the subobjects might need one as well. A no gravity, kinematic one.
I don't understand because you can't add a script to a collider, so where do you put the first script ?
@Gregory2fs The first script, the proxy, should be added to each of the gameobjects representing the parts of the whole object, which also contain a collider component (that was what i meant by subcolliders - children gameobjects of the main gameobject, with coliders attached) It should route the collision messages to the script attached on the main gameobject with an id of the child gameobject that triggered the collision.
O$$anonymous$$, then if I have a single gameobject with several boxcollider inside there's no solution ? Or I need to create several sub gameobject with a collider inside.
@Gregory2fs This method requires a child empty gameobject for each collider needed. The child gameobjects might need other components too, like a rigidbody, and the colliderproxy script with the desired id.
Your answer
Follow this Question
Related Questions
Detect collision/trigger between two body without rigidbody? 3 Answers
CPU cost of using multiple rigidbodies 0 Answers
Collision not working at all [ABANDONED] 4 Answers
Multiple grab locations on 1 game object?,MULTIPLE GRAB LOCATIONS on 1 game object? 0 Answers
box colliders with rigidbodies passing through each other 0 Answers