0
\$\begingroup\$

In the game I'm creating I have a sprite that needs to constantly be facing the mouse, but the sprite also always needs to be facing "up".

Because of the Polygon Collider 2D and Shadow Caster 2D I cannot just flip the sprite. I used to set the localScale.y of the transform to -1 to keep it facing up, but now that's messing up my normal map for the sprite.

My best guess for how to solve this is to find a way to set the transform.eulerAngles.y to 180 when it needs to flip, but because of the Quaternion I use to keep the sprite "pointed" at the mouse, it's not working for me.

How can I solve this?

if (transform.eulerAngles.z > 90 && transform.eulerAngles.z < 270)
{
    direction = Vector2.down;
    antidirection = Vector2.up;
    transform.localScale = new Vector3(transform.localScale.x, -1, transform.localScale.z);
} else
{
    direction = Vector2.up;
    antidirection = Vector2.down;
    transform.localScale = new Vector3(transform.localScale.x, 1, transform.localScale.z);
}

if (isAccelerating) {
    helicopter.AddRelativeForce(direction * power);
}
if (isDeccelerating)
{
    helicopter.AddRelativeForce(antidirection * power);
}

var facing = Input.mousePosition-Camera.main.WorldToScreenPoint(transform.position);
var angle = Mathf.Atan2(facing.y, facing.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
\$\endgroup\$
1
  • \$\begingroup\$ Why not simply create two versions of the sprite (including colliders & shadow casters )-- facing left and right -- and swap them as needed? \$\endgroup\$ Oct 31, 2021 at 20:38

1 Answer 1

0
\$\begingroup\$

If you're going to use Euler angles anyway, and don't need arbitrary 3D rotations where gimbal lock is an issue, then you might as well just stick with Euler angles throughout.

var facing = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
var angle = Mathf.Atan2(facing.y, facing.x) * Mathf.Rad2Deg;


if (facing.x >= 0) {
    // If we're facing to the right, roll counter-clockwise to match.
    transform.eulerAngles = new Vector3(0, 0, angle);
} else {
    // If we're facing to the left, flip on the y axis, then roll clockwise to match.
    transform.eulerAngles = new Vector3(0, 180, 180 - angle); 
}

// Since we're flipping on the y axis, not the x, we don't need to
// swap our directions when flipped anymore.
if (isAccelerating) {
    helicopter.AddRelativeForce(Vector2.up * power);
}
if (isDecelerating) {
    helicopter.AddRelativeForce(Vector2.down * power);
}
\$\endgroup\$
3
  • \$\begingroup\$ This is almost exactly the answer I was looking for! The only problem is that rotating the transform 180 degrees also rotates the local vectors 180 degrees. The control when I'm facing right is correct, but when I'm facing left the control is rotated 180 degrees. \$\endgroup\$
    – Max Bailey
    Oct 31, 2021 at 21:30
  • \$\begingroup\$ You could fix that the same way you did previously with your direction variable. Or you could wrap this object in an empty object that does not rotate, and apply your control logic to that empty object instead. Since you have not shown us the control code, we are not able to anticipate or help you fix problems with it, so that's as much as I can offer you in the current state. \$\endgroup\$
    – DMGregory
    Oct 31, 2021 at 21:32
  • \$\begingroup\$ I fixed using Vector2.Reflect() on the relative vector and Vector2.left and then applying the force regularly, not relatively. Thanks for your help! \$\endgroup\$
    – Max Bailey
    Oct 31, 2021 at 22:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .