I am trying to clamp the rotation of turret’s barrel in an interesting way. The negative elevation of the barrel is 10 degrees, the positive elevation of the barrel is 350 degrees. 0 degrees is straight ahead. All rotations are being done through localEulerAngles as the turret rides on a body which pitches and rolls to follow terrain.
A visual example: Envision pacman with his mouth open. The 0 degree line is drawn out from the center of his mouth. The top of his mouth is 350 degrees. The minimum is 10 degrees. I want to allow a transform to only rotate through the 20 degree range which denotes the open area.
I have attempted to manipulate Mathf.Clamp and various if statements without success, the problem lies with the fact that my minimum rotation is numerically higher than the maximum as a result of the wrapping past zero.
Is there a way to write an if statement of the form “int > var > int” or anything I can do to not allow a range of 11 to 349.
If any more information is needed, or if I’ve omitted anything critical, please let me know.
As you noted, EulerAngles.x is unreliable (and the docs caution against using it.) So, just use your own angle, that you say will be -10 to 10. Unity is just fine setting rotations using negative angles:
float gunDegs = 0; // will be -10 to 10 degrees, of x rotation
// user changes it, and just in case... :
gunDegs = Mathf.Clamp(gunDegs, -10, 10);
gun.localRotation = Quaternion.Euler(gunDegs, 0, 0);
I wrote the following code to rotate a catapult via mouse (left and right) - so I have 2 positive values and it’s a wrapping rotation like yours.
// Get x axis from mouse
float MouseTurn = Input.GetAxis("Mouse X");
// rotate your object in the y axis (left and right)
transform.Rotate(0, MouseTurn * MouseTurnSpeed * Time.deltaTime, 0);
// Set a tracker to check if the angle is in between the values you want
bool InBetween = false;
Vector3 currentRotation = transform.localRotation.eulerAngles; Debug.Log("CURRENT ROTATION: " + currentRotation.ToString());
// Because this is wrapping rotation, I have 2 positive values
if(currentRotation.y > 320.0f &¤tRotation.y <= 360.0f || currentRotation.y >= 0 && currentRotation.y <= 40.0f)
{
InBetween = true;
}
else
{
InBetween = false;
}
// if its outside the range you want, force it back to the closest value within the range and set the rotation via transform.localRotation
if(!InBetween)
{
// Closer to 40
if(Mathf.Abs(currentRotation.y - 320.0f) >
Mathf.Abs(currentRotation.y - 40.0f))
{
currentRotation.y = 40.0f;
transform.localRotation = Quaternion.Euler(currentRotation);
InBetween = true;
}
// Closer to 320
else if(Mathf.Abs(currentRotation.y - 40.0f) > Mathf.Abs(currentRotation.y - 320.0f))
{
currentRotation.y = 320.0f;
transform.localRotation = Quaternion.Euler(currentRotation);
InBetween = true;
}
}
(i had a problem where Mathf.Clamp didn’t work with negative numbers)
So basically the constraining will be -30 and 30 degrees, but since we can’t use Mathf.Clamp(quat.eulerAngles.x,-30,30), we add 180 to all these values, and get Mathf.Clamp((quat.eulerAngles.x+180), 150, 210). But, since over 360 is bad too, we use %360 (it divides the value by 360 and returns the remainder, so 420%360 will return 60), and now it looks like ((quat.eulerAngles.x+180)%360, 150, 210). But in the end we should substract 180 that was previously added, and will get the actual angle that we need. So we get the line of code from the start! Mathf.Clamp((quat.eulerAngles.x+180)%360,150, 210)-180
That will always work with cases when you get “350” instead “-10”.
P.S.: For negative input angles just use +360