- Home /
2D: Rotating to face mouse position with two fixed axes
I'm working on a 2D sidescrolling platformer with keyboard movement and mouse aiming controls. The character's arms should point in the direction of the mouse cursor on the screen, but rotate independently from the body of the character. Additionally, I'd like to have an easy reference to the rotational position of the arms so that I might apply forces in that direction.
Making the arms children of the character object, I can get them to point to the mouse with the script below, but I run into one problem. Whenever the mouse crosses the vertical centre of the screen, the y-rotation of the arms flips, essentially reversing the position of the near and far arms of the character. This also has the side effect of altering the x-rotation, making it so I can't count on anything related to it to act as expected in world space.
Is there a better way to do this?
function Update (){
var mousePos = Input.mousePosition;
mousePos.z = 10.0f; //The distance from the camera to the player object
var lookPos : Vector3 = Camera.main.ScreenToWorldPoint(mousePos);
transform.LookAt(lookPos);
}
Answer by robertbu · Mar 06, 2013 at 03:17 AM
I think this is what you are looking for, or at least a start. It is different for the code above in that it aligns the right of the object (as opposed to the forward) with the mouse. If your object is not authored that way, you might be able to fix it by making the arms children of an empty game object and attaching the script to the empty game object.
As for adding force in the direction of the arms, depending on your frame of reference it will be either transform.right or -transform.right.
function Update () {
var mousePos = Input.mousePosition;
mousePos.z = 10.0f; //The distance from the camera to the player object
var lookPos : Vector3 = Camera.main.ScreenToWorldPoint(mousePos);
lookPos = lookPos - transform.position;
var angle : float = Mathf.Atan2(lookPos.y, lookPos.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
Interesting! I'd never thought to align it anywhere except along the z axis, but this certainly does the job. For some reason, though, this conditional never returns true, despite the rotation values being visibly within that range:
if ((transform.rotation.z <=270) && (transform.rotation.z >=90))
Should I be accessing the right/left split differently?
'transform.rotation' is a Quaternion. Unless you understand Quaternions, it is recommended you not read values or set values. You can use transform.eulerAngles, though you have to be careful there as well. Quoted from the reference for eulerAngles:
Do not set one of the eulerAngles axis separately (eg. eulerAngles.x = 10; )
And as for reading, multiple different combinations of euler values can add up to the same rotations.
Here's one way to access the left/right split:
if (Vector3.Angle(Vector3.right, transform.right) <= 90)
// Do the right point stuff;
else
// Do the left pointing stuff
Vector3.Angle() returns an unsigned angle between two vectors. This code compares the world right with the 'right' vector of the game object.
Ah! That does it! Thanks a lot for all your help. I'm going to take a few good notes form all this for my ongoing and future reference. Again, very much appreciated.
Your answer
Follow this Question
Related Questions
Can someone help me fix my Javascript for Flickering Light? 6 Answers
Setting Scroll View Width GUILayout 1 Answer
Locking move direction and rotation in JavaScript 1 Answer
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
How to tell if two objects are right next to each other in a 2d game? 2 Answers