- Home /
How do I get reflection vector from a 2D collision
Ok I am trying to do what I thought would be a simple bouncing bullet. Bullet hits wall, bounces off like a laser. I have now been at this for six hours. I was found this: http://answers.unity3d.com/questions/350431/vector3reflect-wrong-direction.html and tried to reverse engineer the code but it is not working correctly for me.
Their Code (adapted for Physics2D):
function drawLaser(startPoint:Vector3,n:int)
{
var hit : RaycastHit2D ;
var rayDir:Vector3 = Spawner.transform.up;
for(var i = 0; i < n; i++)
{
hit = Physics2D.Raycast (startPoint, rayDir, 1000);
if (hit.collider != null)
{
Debug.DrawLine (startPoint, hit.point, Color.red, 0.1, false);
rayDir = Vector3.Reflect( (hit.point - startPoint).normalized, hit.normal ) ;
startPoint = hit.point;
}
}
}
Now the thing that has me really confused is the above code works perfectly fires the little laser and bounces off the walls. But when I try to use the same calculation on my projectile, it derps of whatever which way it feels like. Code for my projectile here:
function OnCollisionEnter2D(coll: Collision2D)
{
if(coll.collider.GetComponent(Health) != null)
{
coll.collider.GetComponent(Health).Hurt(Dammage);
}
if(PingCount <= 0)
{
Destroy(gameObject);
}
else
{
var dir = Vector3.Reflect( (coll.contacts[0].point - transform.position).normalized, coll.contacts[0].normal);
var angle : float = Mathf.Atan2(-dir.x,dir.y) * Mathf.Rad2Deg;
var targetRot = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = targetRot;
}
PingCount -= 1;
}
I would really appreciate it if someone could explain what I am doing wrong. Thanks in advance : )
PS: All of this is using physics2d
Oh, also in case you are wondering, the reason I am using a Vector3.Reflect when everything else is in 2D is because Vector2.Reflect does not exist. Similarly that little knot of code at the bottom is for pointing the object to face in the direction a vector is pointing without flipping my 2D object sideways making it invisible.
That still did not work for me for some reason. It looked like it was doing the same thing as the previous script.
Answer by CiberX15 · Aug 31, 2014 at 07:05 PM
I don't know if this is the best solution but the following is how I got it to work for my purposes. Basically, I could not figure out how to get the reflection vector from the collision. However I had a perfectly working example of how to do it with simple lines and ray casts. So I cheated. The projectile now casts a ray in front of it and when the ray hits something it does the calculation figures out the reflection vector and then rotates to face that vector.
The Code:
function PingOff()
{
var hit: RaycastHit2D = Physics2D.Raycast (transform.position, transform.up, 0.5, hitMask);
if (hit.collider != null)
{
//Calculate ping
var rayDir : Vector3 = Vector3.Reflect( (hit.point - transform.position).normalized, hit.normal ) ;
if(hit.collider.GetComponent(Health) != null)
{
hit.collider.GetComponent(Health).Hurt(Dammage);
}
if(PingCount <= 0)
{
Destroy(gameObject);
}
else
{
//Ping off
var dir : Vector3 = rayDir;
var angle : float = Mathf.Atan2(-dir.x,dir.y) * Mathf.Rad2Deg;
var targetRot = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = targetRot;
}
PingCount -= 1;
Dammage = Dammage * 2;
}
}
@CiberX15 Hi there, I would like to ask a question as well, didnt want to start another thread. I'm working on 2D game, which when I shoot bullet it will reflect and the bullet will disappear after a couple bounces. How would I do that? Thank you.
So this solution worked except when my ray wasn't hitting the object, since my collider could be wider than the ray. Like a glancing blow. To Fix this I did the following
cast a ray from the center first
if that raycast missed cast a ray from the bottom of the collider
if that raycast missed cast a ray from the top of the collider
public static Vector2 getReflectVelocity(Transform bulletTransform, Vector2 velocity, Collider2D col, Collider2D bulletCollider) { Vector3 direction = velocity.normalized; Vector3 rayOrigin = bulletTransform.position - (direction * 1f); //Try hitting from the center of the projectile RaycastHit2D hit = Physics2D.Raycast(rayOrigin, direction, 2, 1 << col.gameObject.layer); //We missed - Try hitting on bottom of projectile if(!hit) { Bounds bounds = bulletCollider.bounds; rayOrigin = new Vector3(bounds.center.x, bounds.$$anonymous$$.y) - (direction * 1f); hit = Physics2D.Raycast(rayOrigin, direction, 2, 1 << col.gameObject.layer); } //We missed - Try hitting on top of projectile.. if(!hit) { Bounds bounds = bulletCollider.bounds; rayOrigin = new Vector3(bounds.center.x, bounds.max.y) - (direction * 1f); hit = Physics2D.Raycast(rayOrigin, direction, 2, 1 << col.gameObject.layer); } if(hit) return Vector2.Reflect(velocity, hit.normal); //Welp we tried.... else return -velocity; }
In that case you might want to use Physics2D.CircleCast(). It acts like a raycast but you can give it a radius. This would save you from having to make multiple checks, and also guard against the edge case where your projectile should be bouncing off something that fits between the raycasts.
https://docs.unity3d.com/ScriptReference/Physics2D.CircleCast.html
Your answer
Follow this Question
Related Questions
How do i make something reflect in 2D? 1 Answer
2D - more lights 2 Answers
How to Create Still Water Reflections [2D] C# 0 Answers
2D Dynamic Reflections ReadPixel Issue 0 Answers