# Limit rotation to certain angles for transform.rotate

I'm working on a small project to learn Blender and Unity, and one issue I recently came across is that while I can have the turret of my tank rotate on the z-axis based on mouse movements, I can't for the life of me figure out how to lock it to certain angles.

My current approach was to use Mathf.Clamp to limit the range of values that I could pass to the rotate function, but that doesn't seem to have done anything at all, even though when outputting the value Clamp produces, I can tell it doesn't go over my specification.

The code I have:

enum RotationAxes {MouseX, MouseY, MouseXandY};
var axes : RotationAxes;
private var MouseX = RotationAxes.MouseX;
var sensitivityX : float = 15F;
var minimumZ : float= -35;
var maximumZ : float = 35;
function Update ()
{

if (axes == MouseX)
{
//yRotation += Input.GetAxis("Mouse X");
//transform.eulerAngles = Vector3(0, 0, yRotation);
transform.Rotate(0, 0, Mathf.Clamp (Input.GetAxis("Mouse X")*sensitivityX, -30, 30));

}

}

function Start ()
{

}

• Remember that transform.Rotate says "rotate this far from where you are currently" — so it can stack up over the course of many frames. (Eg. If I rotate by 1 degree each frame at 30 fps, then in two minutes I'll have rotated through a full circle). If you want to set an absolute rotation rather than a relative change in rotation, you can assign a value to the transform's rotation or localRotation parameters. (These are quaternions, but you can convert from Euler angles with Quaternion.Euler()) – DMGregory Jan 13 '17 at 20:45
• You're absolutely right, but do you have any suggestions on how to alter the code to accommodate your solution? – Michael Kaesy Jan 13 '17 at 20:54

Here's one way to approach it.

// Inspector parameters to control how we rotate.
var axisName     : String  = "Mouse X";
var sensitivity  : float   = 15f;
var minAngle     : float   = -30f;
var maxAngle     : float   = 30f;
var rotationAxis : Vector3 = new Vector3(0, 0, 1);

// Remember the original orientation of the object so we can rotate relative to that.
private var _initialRotation : Quaternion;

// Track the desired rotation angle over time.
// Note that this only works well for one axis.
// If combining multiple axes of rotation we'll usually want to store a Quaternion instead.
private var _currentAngle : float = 0f;

function Start() {
// Cache the orientation of the object once it's spawned.
// This lets us rotate relative to its placed orientation in a scene.
_initialRotation = transform.localRotation;
}

function Update() {
// Calculate the desired rotation angle by adding this frame's delta:
_currentAngle += Input.GetAxis(axisName) * sensitivity * Time.deltaTime;

// Clamp the rotation angle within the allowed range.
_currentAngle = Mathf.Clamp(_currentAngle, minAngle, maxAngle);

// Create a rotation about the desired axis using the clamped angle.
// You could use Quaternion.Euler; I chose this route to support diagonal axes too.
var rotation : Quaternion = Quaternion.AngleAxis(_currentAngle, rotationAxis);

// Apply the rotation to our object.
// Using localRotation means we don't override rotation from the parent hierarchy.
// Putting rotation last means we rotate around the object's local axes.
transform.localRotation = _initialRotation * rotation;
}

• Now if only I could translate it to Javascript :D – Michael Kaesy Jan 14 '17 at 11:55
• It's a pretty direct replacement, as you can see. No "if only" required. Just take public float foo = 123 and make it var foo : float = 123, add a private for anything that's not public, replace void with function and change string to String. – DMGregory Jan 14 '17 at 16:27
• Works brilliantly! – Michael Kaesy Jan 14 '17 at 18:48

You could have an if statement in update that is like this: if (EulerAngles.x >= maximumx) { EulerAngles.x == maximumx; } then, vise versa for the minimum rotation, but have it at a less than.

You basically have it, but you need to set the rotation instead of adding to it. Try this.

transform.rotation = Quaternion.Euler(0, 0, Mathf.Clamp (transform.eulerAngles.z + Input.GetAxis("Mouse X")*sensitivityX, -30, 30));


Edit: Also, don't forget to multiply the input value by Time.deltaTime to make the rate of rotation framerate independent.

• This is close, but transform.rotation.z gives you the z component of the rotation Quaternion, not the euler angle representation. This can give you unexpected results, since the xyz components of a Quaternion don't directly map to angles. You probably want transform.eulerAngles.z instead. – DMGregory Jan 14 '17 at 0:15
• Thanks for pointing that out. I've updated my answer accordingly. – wenright Jan 14 '17 at 2:27
• This gives me interesting output. Turret is pointing upwards in the same direction no matter how I drive the tank, which I think is changed easily enough, but it seems like as soon as I go back to angle 0 the turret clips back to 10 or something, and doesn't want to go to -30. – Michael Kaesy Jan 14 '17 at 10:47
• transform.rotation = Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, Mathf.Clamp(transform.eulerAngles.z + xPos, -30, 30)); ------ is what I currently have, and it gives me the same kind of 360 rotation as before. Any ideas? – Michael Kaesy Jan 14 '17 at 13:52
• xPos = Input.GetAxis("Mouse X")*sensitivityX*Time.deltaTime – Michael Kaesy Jan 14 '17 at 14:00