- Home /
Wrapping Euler Angles To Achieve Mouse Look
I am attempting to limit the player's view at the x euler angle of -80 and 80 (not final values), to prevent the player looking upside down. I do this by "wrapping" the values so I can work with angles in the range of -90 to 90 instead of 90 to 0 and 270 to 360 which aren't good for clamping the values, which I also do (360 degrees will now be -90 and so on). That clamp part works just fine.
Please consider the following code:
var wrappedX : float;
Inside update function:
transform.localEulerAngles = Vector3(Mathf.Clamp (wrappedX, -80, 80), 0, 0);
if (transform.localEulerAngles.x >= 270) { wrappedX = transform.localEulerAngles.x - 360; } else { wrappedX = transform.localEulerAngles.x; }
print(Vector3(Mathf.Clamp (wrappedX, -80, 80), 0, 0));
It appears to be working fine except for the part where I actually assign the x euler angle as the new clamped value In this part of the code that you also read above:
transform.localEulerAngles = Vector3(Mathf.Clamp (wrappedX, -80, 80), 0, 0);
For some reason the player's x euler angle is forced to 0, therefor the player can only look side to side (handled in other code not shown), and not up or down at all. the player's view is stuck at 0 degrees.
So what specifically am I doing wrong here? I am very new to angles and stuff so exact code on what will fix it is perfered. Can anyone help me out here? Thanks.
EDIT: After more testing I have concluded that the problem is not that code, but the way it combines with this code:
transform.Rotate (lookSpeed * -Input.GetAxis ("Mouse Y"),0, 0)
This is causing the player's view to not be able to move.
Answer by Joshua · Apr 29, 2011 at 12:36 AM
What you're doing wrong is that you're using Eulerangles in a way you should not. As you can see here, you should directly set them to an absolute value and not increment them.
"Only use this variable to read and set the angles to absolute values. Don't increment them, as it will fail when the angle exceeds 360 degrees. Use Transform.Rotate instead."
I guess you could work around this by when ever it exceeds 360 or get's lower then 0, use modulo.
var x = 740;
var moduloX = 740 % 360 //which is 20;
But I advice just using transform.Rotate.
edit: do it like this:
var minimumX : float = -360; var maximumX : float = 360;
var rotationX : float = 0;
private var originalRotation : Quaternion;
function Update () { rotationX += Input.GetAxis("Mouse X") sensitivityX; rotationX = ClampAngle (rotationX, minimumX, maximumX); xQuaternion = Quaternion.AngleAxis (rotationX, Vector3.up); transform.localRotation = originalRotation xQuaternion; }
and include the ClampAngle function of course (my bad, sorry):
static function ClampAngle (angle : float, min : float, max : float) : float {
if (angle < -360.0)
angle += 360.0;
if (angle > 360.0)
angle -= 360.0;
return Mathf.Clamp (angle, min, max);
}
Can you elaborate on how I would use transform.Rotate in this situation specifically?
I'd advice just checking out the mouseLook script that comes standard with Unity. It does exactly this for both x and y with a variable clamp. Just distill from there. :)
It doesn't "increment" in script but you can change the value in the inspector as you like and if you assign values smaller than 0 or greater than 360 to eulerAngles the assignment will fail (and as far as i can remember the quaternion turns to identity [0,0,0]). Quaternions have been invented to circumvent such problems by adding another dimension. This script should work fine. Btw, original rotation is only needed if you have a different startrotation. If you want assign an absolute rotation just assign the result of AngleAxis to localRotation.
Answer by superpig · May 03, 2011 at 09:45 AM
That's a rather odd sequence of operations you've got going on there. Why not get the 'wrappedX' variable to have the right value first, and then use it to set up localEulerAngles?
wrappedX += Input.GetAxis("Vertical"); while(wrappedX > 180) wrappedX -= 360; while(wrappedX < -180) wrappedX += 360; wrappedX = Mathf.Clamp(wrappedX, -80, 80);
transform.localEulerAngles = new Vector3(wrappedX, 0, 0);
That way you'll be more easily able to watch the value of wrappedX in the inspector.
Oh, now I see your answer... yes, that's his problem :)
@Joshua - please don't edit my answers without at least leaving a note as to what you've changed.
Oh, I'm sorry - I just changed the last sentence's grammar because it seemed wrong to me xD and I gave you my upvote to by the way ;). Also - you can check what I did for yourself if you click edit and check the revision history.
Answer by Edy · May 20, 2011 at 11:19 PM
Here is an universal ClampAngle function that accepts euler angles works properly in any situation and any input values:
function ClampAngle (a : float, min : float, max : float) : float
{
while (max < min) max += 360.0;
while (a > max) a -= 360.0;
while (a < min) a += 360.0;
if (a > max)
{
if (a - (max + min) * 0.5 < 180.0)
return max;
else
return min;
}
else
return a;
}
It's not mine, I found it somewhere (maybe at UnifyCommunity, don't remember). I had problems with all other angle clamp methods, especially when smoothing the camera movement. But the above function is the only one that worked properly.
Answer by Quazistax · May 07, 2011 at 01:47 AM
:D
let's see....
You declare variable, and it's initial value is 0.
var wrappedX : float;
Then you assign rotation to transform, creating Vector3(0,0,0).
transform.localEulerAngles = Vector3(Mathf.Clamp (wrappedX, -80, 80), 0, 0);
Then you read that rotation (0,0,0) and compute value to assign to wrappedX, value that will be always 0.
if (transform.localEulerAngles.x >= 270) {
wrappedX = transform.localEulerAngles.x - 360;
}
else {
wrappedX = transform.localEulerAngles.x;
}
And in new Update call, you do it all over again, wrappedX is still 0, and you reset localRotationAngles to (0,0,0).
Ehm, the variable wrappedX get's assigned a value in the inspector. Do you realize it's placed outside the update function? o.O
Hm, then he should supply more information, where, how and what he assigns to it... seems like problem is somewhere out there :) Because, his results are like wrappedX is never set, or set to 0. Of course, I don't exclude some other possibility, but this one should be checked first.
wrappedX gets assigned properly when the game runs.
$$anonymous$$ore information was added to the original post.
Your answer
Follow this Question
Related Questions
Rotation losing precision 0 Answers
Rotation around z-axis always local space and not world? Vector-axis angle projection calcuations. 0 Answers
Aligning/mapping angles of Input.GetAxis(with .localEulerAngles 0 Answers
Problem when checking a Quaternion Eulerangle axis 1 Answer
localEulerAngles.x changes when the angle is close to -90 in the inspector 2 Answers