- Home /
rotation, vector bounce problem
Problem visualized: https://imgur.com/a/8ZEEuyc
Code
void OnCollisionEnter2D (Collision2D collision)
{
Vector2 normal = collision.GetContact(0).normal;
Vector3 reflect = Vector3.Reflect(transform.up, normal);
transform.rotation = Quaternion.LookRotation(reflect);
}
Everytime the object hits a platform it should bounce off of it. The red line represents the expected result, the blue lines the current result in the pic. Since the game is 2D, i only want to rotate on the z axis, not on x or y.
Answer by Bunny83 · Dec 28, 2019 at 12:45 PM
Well, LookRotation calculates a 3d rotation and alignes the forward axis (z - axis) with the first vector you provide and also rotates this forward axis so that the up vector is aligned with the given up vector in the second parameter. If you are in a 2d environment your usage of LookRotation is completely wrong. You do not pass any up vector so you implicitly use Vector3.up.
As you said in 2d you don't want any rotation beside around the fix z axis. In many cases people don't use LookRotation at all in 2d since it wasn't meant to be used in 2d. It's common to use Mathf.Atan2 to calculate the angle a certain direction vector describes with the world x axis. However you can use LookRotation as well. Though you have to pass Vector3.forward as first parameter since you want to keep the forward axis aligned with the world forward axis. Instead you want to pass your 2d direction vector as second parameter which describes the up vector.
Note that if your "desired" direction vector should not be aligned with the objects up vector but with its right vector you just have to rotate your vector 90 clockwise. Since we work in 2d that's trivial since you just have to swap the x and y components and flip the sign of one of them. Which one controls in which direction you rotate (clockwise or counterclockwise).
Assuming you want to align the objects up vector in the direction you specify, you want to do:
Vector2 normal = collision.GetContact(0).normal;
Vector3 reflect = Vector3.Reflect(transform.up, normal);
transform.rotation = Quaternion.LookRotation(Vector3.forward, reflect);
If this doesn't work we need to know more about your object alignment.
Passing the reflection vector as the second argument in lookrotation worked very well. Out of curiosity, you mentioned earlier about generally not using lookrotation in 2D environments, and ins$$anonymous$$d using $$anonymous$$athf.Atan2. So I tried this approach (just to learn):
Vector3 normal = collision.GetContact(0).normal;
float angle = $$anonymous$$athf.Atan2(normal.y, normal.x) * $$anonymous$$athf.Rad2Deg - 90f;
transform.rotation = Quaternion.Euler(transform.forward * angle);
I am not really sure how $$anonymous$$athf.Atan2 works, but this pretty much rotates the object in the normal direction of the hit. How would I reflect it?
Well, LookRotation calculates a quaternion in 3d space. You always have to provide two 3d vectors and the calculation of the quaternion requires quite a few calculations. In 2d things are much more simple since we only have a single rotation plane. Atan2 is a simple extension of the trigonometric function Atan. It simply calculates Atan(y / x)
but in addition it calculates the correct quadrant based on the signs of x and y so we get a full 360° angle ins$$anonymous$$d of just 180° / 90° due to symmetry.
In 3d it's generally easier to work with direction vectors or quaternions since 3d rotations can be quite complex. In 2d it's often easier to just work with angles since there is only one angle. Using Atan2 to get the angle from a 2 component vector is extremely simple.
About your code: You shouldn't use the normal in Atan2 but your reflected vector. All your reflection code is correct. Atan2 is just used to convert a direction vector into a rotation angle
float angle = $$anonymous$$athf.Atan2(reflect.y, reflect.x) * $$anonymous$$athf.Rad2Deg - 90f;
transform.rotation = Quaternion.Euler(0, 0, angle);
Note that you used transform.forward * angle
which makes no sense. transform.forward is a direction vector. Euler angles are not a vector. You can store the 3 euler angles in a Vector3 for convenience, but they do not represent an euclidean vector (a direction or position). Euler angles are just 3 consecutive rotations carried out one after the other. The order of these rotations is important. Unity's euler angles are YXZ in local coordinates or ZXY in world coordinates. So the unrotated object is first rotated Z degrees around the world Z axis, then rotated X degrees around the world x axis and finally Y degrees around the world Y axis
Thanks a lot for these detailed responses and explanations. Your work is appreciated.