- Home /
Precise rotation based on joystick axis input for twin-stick controls
I'm hoping somebody will throw me a bone here. I've searched the fora and haven't found anything that solves my dilemma.
I have a character controller that gets a Direction Vector based on joystick input, then rotates the character using that Direction Vector:
public Vector3 DirVector { get; set; }
Direction += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
transform.rotation = Quaternion.LookRotation( DirVector );
The problem is when ever it comes within 5 degrees of any 90 angle, it snaps to that angle. This means that the player has no control over ~40 degrees of rotation. Now, I understand that Unity does this internally in order to avoid gimbal lock, however I don't see how gimbal lock can occur if I'm only rotating on the y axis.
So how do I get around this? I know that you can get a character to rotate to a specific angle, using euler angles, that is within the elusive, 5 degree range:
transform.eulerAngles = new Vector3( 0,87,0 );
I guess what I'm asking is, how do I convert a direction vector ie. Vector3(5,0,8); to a y rotation in euler angles? A layman response is preferred since I don't understand trigonometry. Also, in C# please.
Thanks in advance!
Answer by nsejosh · Dec 10, 2012 at 10:18 AM
Transform.eulerAngles = new Vector3( 0, Mathf.Atan2( Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")) * 180 / Mathf.PI, 0 );
Should get you pretty close. Might need a negative sign on one or both of the arguments depending which way your camera is aligned, assuming its axis aligned. If not, the math is a bit harder.
Thank you for your quick response.
Unfortunately, that didn't work. I should be more detailed about how I have things set up. The camera is facing down the z axis.
Using the code you provided, I get an output of 0 when the control stick is to the right, and 3 when the control stick is to the left. If my control stick is in the northern hemisphere I get positive output between 0 and 3. When the stick is in the southern hemisphere, I get output between 0 and -3.
If I alter the code like this
transform.eulerAngles = new Vector3( 0, -$$anonymous$$athf.Atan2( Input.GetAxis("RightV"), Input.GetAxis("Horizontal"))*60 + 90, 0 );
I get close to what I'm trying to achieve, but the numbers don't line up exactly with the control stick. I get roughly -4 when the control stick is in the exact up position. Exactly 90 when in the right position. About 184 when in the down position. It swaps to a negative number when in the left position from roughly 276 to -98 which makes it jump a bit. Then I get negative numbers from left to up. At least the snapping is gone. What am I missing?
sorry, I forget atan2 was in radians but eulerAngles takes degrees ( don't know why they didn't just keep everything in radians ) anyway, try this ( and I'll edit original post ) .eulerAngles = new Vector3( 0, $$anonymous$$athf.Atan2( Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")) * 180 / $$anonymous$$athf.PI, 0 );
It works! This has been bugging me forever now. Thanks again for your help. That's extremely helpful. I'm hoping I can pick your brain a little more though.
Later on I plan to implement camera rotation around the character. how would I achieve the same controls relative to the direction the camera is facing?
Thanks @nsejosh! When everything else failed, this was the answer to rotate hips on LateUpdate with animations in mecanim... been looking for this for days!!! Better than LookAt() or Slerping Quaternions! THAN$$anonymous$$S!!!!
Answer by TonCoder · Oct 14, 2019 at 02:52 AM
Well I know this is old as dirt, buuuut, here's a solution to make an object face the direction you move a joystick to.
var _horizontal = Input.GetAxis("Horizontal");
var _vertical = Input.GetAxis("Vertical");
// Direction pointing to
Vector3 newPos = new Vector3(_horizontal , 0, _vertical);
// Get the current position of object
var currentPos = _rigidbody.position;
// Set the current position plus the position targetting
var facePos = currentPos + newPos;
// Set it
transform.LookAt(facePos);
Thanks man ! you saved me some time & frustration ^^ Just wanna add for those who need this in combination with a rotating 3rd person camera for 3D games:
In an update method:
...
Is$$anonymous$$oving = (this.axisX != 0 || this.axisZ != 0);
if (Is$$anonymous$$oving)
{
Vector3 nullifyY = new Vector3(1,0,1);
Vector3 forward = Vector3.Scale(mainCamera.transform.forward, nullifyY) * (speed * axisZ);
Vector3 side = Vector3.Scale(mainCamera.transform.right, nullifyY) * (speed * axisX);
actor.transform.LookAt(actor.position + forward + side);
}
Answer by nsejosh · Dec 10, 2012 at 09:11 PM
well if the camera changes yaw ( i.e. orients around the character ) then you'll just need to add the camera's yaw in to the yaw of your character as an offset. so get the camera's transform.eulerAngles.y ( since yaw is the y component ) and add that in right after the atan2 result. Again, you might need to play around a bit and throw some negative signs in, or a +180 to make everything work, but that's the basic idea.
Of coarse. I was thinking it was more complicated. Thanks again man.