- Home /
Get direction inside OnCollisionEnter
Hi. Im having trouble getting the exit point of imaginary ray. I have a proyectile which impacts against a spaceship (3D) and if gets heavy damage i want to show a explosion geting out from the contrary direction of the impact.
I use OnColliderEnter(Collider col) from the proyectile, to get the contact point (the red point, see image A.png) which is col.contacts[0].point. I need the yellow point. I thought in raycasting the target collider col.collider.Raycast() with a ray from away against the contact point. But for it i need the direction vector (the green arrow).
Im tried doing something like this:
Vector3 _direction = (col.contacts[0].point - transform.position).normalized;
Vector3 _away_point = col.contacts[0].point + _direction * 1000f;
But i get weird directions, see second image. I think its because trasform.position is modified after the impact is done (so the proyectile bounces and changes its position) but before OnCollisionEnter is called. Im tried with transform.forward but its the same problem
Its the complete code: Vector3 _direction = (col.contacts[0].point - transform.position).normalized; Vector3 _away_point = col.contacts[0].point + _direction * 1000f;
Ray _ray = new Ray(_away_point, -_direction);
RaycastHit _rh;
if(col.collider.Raycast(_ray, out _rh, 1500f))
{
//_rh.point is the needed point
//i need too the direction so i can assign it to the efect
}
Answer by jackmw94 · Jan 30, 2021 at 12:01 AM
Good question!
I don't think the information you have in front of you currently is enough to figure out this information so what else can we know..
It sounds like your bullets are using physics and therefore will have rigidbodies on them, so we can get the rigidbody off the collider's gameobject which has access to it's physical state including things such as velocity.
Now given the point at which the bullet hit and it's velocity - which is a vector direction - we can go about figuring out where the other side of the space ship would be. Instead of trying to find a way to raycast through the ship and find the point at which we leave it, this will be a lot easier if we raycast from a point far enough the other side of the ship pointing back in.
Say ships can't be any larger than 20 units / meters:
private Vector3? FindBulletExit(Transform hitObjectTransform, Vector3 bulletHitPoint, Vector3 bulletVelocity, float maxObjectSize = 20)
{
// hit object transform is the ship itself
// max object size is how far we're going to start our ray, from the bullet hit point
Vector3 rayOrigin = bulletHitPoint + bulletVelocity.normalized * maxObjectSize;
// we start our ray in the direction of the velocity, at distance specified by maxObjectSize
// it's directed in the opposite direction to that in which the bullet was travelling
Ray ray = new Ray(rayOrigin, -bulletVelocity);
// your IDE might tell you to refactor this to the non-alloc version
// this will only happen once a ship's lifetime so not much gain but no harm in doing it
var bulletExitPointHits = Physics.RaycastAll(ray);
float closestHitDistance = float.MaxValue;
int closestHitIndex = -1;
for (var index = 0; index < bulletExitPointHits.Length; index++)
{
var raycastHit = bulletExitPointHits[index];
if (raycastHit.transform == hitObjectTransform)
{
// this hit has hit ship, is it the closest?
float hitDistance = (raycastHit.point - bulletHitPoint).magnitude;
if (hitDistance < closestHitDistance)
{
// if yes, set this as new closest
closestHitDistance = hitDistance;
closestHitIndex = index;
}
}
}
if (closestHitIndex == -1)
{
Debug.LogError($"FindBulletExit could not find opposite side of object {hitObjectTransform.gameObject} at {maxObjectSize}m from hit");
// if none of our hits hit the transform we specified we'll have to return null
// make sure you handle this possibility where you call this code
return null;
}
// this is the point on the other side of the gameobject
// the direction of the explosion will be the same direction as the bullet velocity
return bulletExitPointHits[closestHitIndex].point;
}
We use RaycastAll instead of Raycast because there might be multiple points at which the line running through your object might re-enter your object. Such as if there was a large barrelled gun on your ship, you wouldn't want the exit explosion to come out of the barrel, rather the hull which will be the closer hit.
I haven't tested this code, half because I am lazy and half because it's there for you to see the process. If you're struggling to debug problems involving vectors and directions, I don't blame ya, humans aren't all that good at looking at 3 floating point numbers and figuring out how that relates to another set of 3 floating point numbers in 3D space. SO unity give us the ability to write our own gizmos. Just like you have Start, Awake and Update - monobehaviours also provide functions called OnDrawGizmos and OnDrawGizmosSelected which allow us use of the Gizmos library. From here you can draw cubes, spheres, lines, etc that will show up in your scene during edit / play mode. Seeing the intensions of your code in actual space is so damn useful when writing any code like this - if the code doesn't work then use these to solve it!
Thanks for your time. I will try those gizmos, i used them once, but i forget it. I will have it in $$anonymous$$d for other things. The problem was getting the direction of the proyectile inside OnCollisionEnter. Tried transform.forward, transform.position, rigidbody velocity, but they are all modified after impact. (so doing something like Vector3 rayOrigin = bulletHitPoint + bulletVelocity.normalized * maxObjectSize; i get the direcction after impact (rotated)
I found the solution saving a copy of transform.forward (proyectile) 1 frame before, using a coroutine. I found another coroutine from the base class where i can put the line without creating another. I think its the only way, anyways no worries, it runs ok
Good workaround! If you find this gets a bit messy then an alternative could be to make your bullets triggers only. This is only applicable if they don’t need to bump into things, if they only need the collider to detect when they hit their target. This will mean that when it does hit it won’t bounce of the hull of the ship and therefore its direction, either forward or velocity, will be accurate. There is a check box on the collider to set it as a trigger and then change your bullet collision detection to “OnTriggerEnter” instead of “OnColliderEnter” :)
Answer by diegonv · Jan 29, 2021 at 11:02 PM
Im resolved it by using a coroutine like this:
private IEnumerator asd() { while(true){ _previous_direction = transform.forward; yield return null; } }
It seems to save the direction before physics, but im not sure if always. And every proyectile will have one more coroutine running. If anyone knows a better way please write
Your answer
Follow this Question
Related Questions
raycast position & directions 1 Answer
Move point in the direction of another 1 Answer
If collider between two points get this point 1 Answer
Magic Leap Raycasting - Direction 2 Answers
get the point directly above the raycast collision? 1 Answer