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 ()

  • \$\begingroup\$ 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()) \$\endgroup\$ – DMGregory Jan 13 '17 at 20:45
  • \$\begingroup\$ You're absolutely right, but do you have any suggestions on how to alter the code to accommodate your solution? \$\endgroup\$ – 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;
  • \$\begingroup\$ Now if only I could translate it to Javascript :D \$\endgroup\$ – Michael Kaesy Jan 14 '17 at 11:55
  • \$\begingroup\$ 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. \$\endgroup\$ – DMGregory Jan 14 '17 at 16:27
  • \$\begingroup\$ Works brilliantly! \$\endgroup\$ – 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.

  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – DMGregory Jan 14 '17 at 0:15
  • \$\begingroup\$ Thanks for pointing that out. I've updated my answer accordingly. \$\endgroup\$ – wenright Jan 14 '17 at 2:27
  • \$\begingroup\$ 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. \$\endgroup\$ – Michael Kaesy Jan 14 '17 at 10:47
  • \$\begingroup\$ 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? \$\endgroup\$ – Michael Kaesy Jan 14 '17 at 13:52
  • \$\begingroup\$ xPos = Input.GetAxis("Mouse X")*sensitivityX*Time.deltaTime \$\endgroup\$ – Michael Kaesy Jan 14 '17 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.