- Home /
The question is answered, right answer was accepted
Mathf.Clamp Negative min not negative?
Started a new project last week and decided to take a new approach to character movement and rotation and to bind the look up and down angles im trying to use Mathf.Clamp which i've used before but for some reason it doesn't like that negative min as it won't allow the rotation to go to -40 only to zero and then snaps the rotation to positive 40 which is very strange. Also note the camera is a child of a game object, and i'm trying to modify its y axis locally which is why I use local rotation.
Here is the code, I'm sure its something very simple and i'm just being blind but I have tried everything I can think of.
public class Rotation : MonoBehaviour
{
[Range(0, 10)]
public float rotationSpeed;
public Camera cam;
void Update ()
{
float rotateX = Input.GetAxis ("Mouse X");
float rotateY = -Input.GetAxis ("Mouse Y");
transform.Rotate (0, rotateX, 0);
rotateY *= rotationSpeed;
cam.transform.Rotate (rotateY, 0, 0);
Vector3 rot = cam.transform.localRotation.eulerAngles;
rot.x = Mathf.Clamp (rot.x, -40, 40); //<--- Negative 40 not working :(
//Debug.Log (rot);
cam.transform.localRotation = Quaternion.Euler (rot);
}
}
The problem is that you are passing in an int and two floats. There is no prototype for that. $$anonymous$$ake sure that data types are of the same type, so cast your -40, 40 via -40f, 40f and all should be good.
Answer by LiloE · Feb 25, 2017 at 09:35 PM
Assuming the problem is at the rotation component, did you try this?
var xRotation = Mathf.Clamp (rot.x, -40, 40);
if (xRotation < 0) xRotation = 360 + xRotation; // e.g. 360 + -40 = 320 which is the same rotation
rot.x = xRotation;
That would work although I still don't see why what I currently have setup is not working? does $$anonymous$$athf.Clamp just not like negative values and you have to use the whole positive 360 spectrum?
Unity does not store rotations as eulerangles but as quaternions. Whenever you access eulerangles it converts the quaternion to eulerangles. Likewise when you set the eulerangles it converts them back to a quaternion. The eulerangles representation is not unique. $$anonymous$$ost rotations can be expressed in at least two different ways with euler angles. So are you sure that rot.x is actually ever negative? $$anonymous$$ost likely not.
$$anonymous$$athf.Clamp does work as expected. It is literally implemented this way:
// taken from UnityEngine.dll
public static float Clamp(float value, float $$anonymous$$, float max)
{
if (value < $$anonymous$$)
{
value = $$anonymous$$;
}
else
{
if (value > max)
{
value = max;
}
}
return value;
}
This is a bit old, but it's still actual.
Just to confirm that Unity $$anonymous$$athf.Clamp only limits its floats values to anything between 0 and 1.If you try to Clamp any number below 0 as a $$anonymous$$imum, it will be changed to 0 and anything higher than 1 will be change to 1.
So... $$anonymous$$athf.Clamp(V, -0.5f, 1f) will return a number between 0f and 1f; $$anonymous$$athf.Clamp(V, -0.5f, 0f) will return only return 0f; $$anonymous$$athf.Clamp(V, -0.5f, 2f) will return a number between 0f and 1f; $$anonymous$$athf.Clamp(V, 0.5f, 10f) will return a number between 0.5f and 1f;
The same principle will apply if you invert the $$anonymous$$imal and maximal value, but in reverse.
You can counter this limitation by applying, initially, a division so that the float gets below 1.0f. For coordinates, depending on how "big" your scene is, you could take the Vector3, divide it by 1000 (if your scene doesn't have anything further than 9999 units from the center), do whatever $$anonymous$$ath.Clamp you need, then multiply back the result by 1000.
If you got negative values, you can overcome it doing some good old maths tricks.
With the example of the degrees, you know that then are a maximum of 360 degrees on both direction (720 degrees in total), so you can simply do something like this:
You're original script which is this rot.x = $$anonymous$$athf.Clamp (rot.x, -40, 40); $$anonymous$$ostly means you want to limit the degrees between -40 and 40 degrees, right?
If you were to convert that in another format, you could say that it's between 320/720 and 400/720. 320 represents -40 over the range between -360 and 360 available degrees while 400 represents 40.
Here's a quick and easy way of making this work:
rot.x = ($$anonymous$$athf.Clamp(rot.x, (360 + ValueA)/720, (360 + ValueB)/720) * 720) -360;
// ValueA is your -40 and ValueB is your 40.
This will work as long as you set your rotation value within the 360 degrees range. If you something that can work with something that exceed 360 degrees range, such as with movement like a 1080 degrees movement tricks for some kind of sport game, you simply got to analyse how big the player can reach within your game's scope. You can then simply change the 360 & 720 values above by something that reaches your goal. For example, 1080 degrees means 2160 total possible rotation... so you change the 360 for 1080 and the 720 for 2160 and you got yourself a Clamp for 1080 degrees.
The only limit comes from the usual float precision that might start giving out slight errors with the latest 2 digits of the number you get from the division. That's why you might not want, just for the sake of it, to push the limit too high. It's not like you'll need -10,000 to 10,000 degrees unless your game involve one hell of a fast paced rotation speed that can exceed 360 degrees per frame.
No, this makes no sense. Did you read my comment? I've posted the exact implementation of Clamp. You can look it up yourself here. Your issue is related to the quaternion to Euler angles conversion. When you carry out any tests make sure you check your actual input values
Follow this Question
Related Questions
Flip over an object (smooth transition) 3 Answers
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Twin Stick Shooter controller 0 Answers
RotateAround reversing doesn't work with negative vector3 0 Answers