How to clamp rotation

I have a script to allow the camera to move up and down, but the problem It will go in a complete circle if I move the mouse all the way up or down. How do I stop it from going around and limit it to looking almost completely down to looking completely up.

Script C#

public GameObject target;
public float rotateSpeed = 5;
Vector3 offset;

// Update is called once per frame
void Update () {
		
	Vector3 rot = transform.eulerAngles;
	
	float vertical = Input.GetAxis ("Mouse Y") * rotateSpeed;
	target.transform.Rotate (-vertical, 0, 0);
	
	float desiredAngle = target.transform.eulerAngles.y;
	Quaternion rotation = Quaternion.Euler (desiredAngle, 0, 0);
	transform.position = target.transform.position - (rotation * offset);
	rot.x = Mathf.Clamp(rot.x + -45, 0, 0);
	//transform.eulerAngles = rot;
	
	
	transform.LookAt (target.transform);
		

}

First of all I’d like to say that this is the MouseLook.cs file from the Unity Standard Assets FirstPersonController. It does exactly what you are looking for (besides allowing the camera to look in all directions which can be easily changed). It should be easy to adapt to your use.

LookRotation() is called at an Update() method of any script attached to the gameobject the camera is attached to, with the following parameters:

  1. Transform of the gameObject, the camera is attached.
  2. Transform of the main camera (Camera.main.transform).

(If you decide to use the script do not forget to call the Init() at the Start method.)

public class MouseLook
    {
        public float XSensitivity = 2f;
        public float YSensitivity = 2f;
        public bool clampVerticalRotation = true;
        public float MinimumX = -90F;
        public float MaximumX = 90F;
        public bool smooth;
        public float smoothTime = 5f;

        private Quaternion m_CharacterTargetRot;
        private Quaternion m_CameraTargetRot;

        public void Init(Transform character, Transform camera)
        {
            m_CharacterTargetRot = character.localRotation;
            m_CameraTargetRot = camera.localRotation;
        }

        public void LookRotation(Transform character, Transform camera)
        {
            float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * XSensitivity;
            float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSensitivity;

            m_CharacterTargetRot *= Quaternion.Euler (0f, yRot, 0f);
            m_CameraTargetRot *= Quaternion.Euler (-xRot, 0f, 0f);

            if(clampVerticalRotation)
                m_CameraTargetRot = ClampRotationAroundXAxis (m_CameraTargetRot);

            if(smooth)
            {
                character.localRotation = Quaternion.Slerp (character.localRotation, m_CharacterTargetRot, smoothTime * Time.deltaTime);
                camera.localRotation = Quaternion.Slerp (camera.localRotation, m_CameraTargetRot, smoothTime * Time.deltaTime);
            }
            else
            {
                character.localRotation = m_CharacterTargetRot;
                camera.localRotation = m_CameraTargetRot;
            }
        }

        Quaternion ClampRotationAroundXAxis(Quaternion q)
        {
            q.x /= q.w;
            q.y /= q.w;
            q.z /= q.w;
            q.w = 1.0f;

            float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan (q.x);
            angleX = Mathf.Clamp (angleX, MinimumX, MaximumX);
            q.x = Mathf.Tan (0.5f * Mathf.Deg2Rad * angleX);

            return q;
        }
    }

I’m new to this as well, but I did something similar yesterday, try replacing your rot.x = Mathf.Clamp(rot.x + -45, 0, 0); with:

rot.x = Mathf.Clamp(rot.x, -20, 45);

Where -20 is the lowest it can go and 45 is the highest.

Let me know how you go, keep in mind I’m no expert, just thought I’d see if this helps you.

Another approach you can take is to consider a level baseline and use a float to keep track of your current rotation. Why? Well, there are two reasons to consider this approach:

  1. Upper and lower limits can be maintained and enforced at any angle (with proper accommodation for a “current” facing)

  2. You aren’t subject to Gimbal Lock when looking beyond straight up or down

Here’s a basic idea of what would need to be implemented (though this probably won’t work on its own):

// C#
public float minYRotation = -70.0f;
public float maxYRotation = 92.0f; // For proof of concept, basically
float currentRotation = 0.0f;
Quaternion yRotation;

void Update()
{
	currentRotation += Input.GetAxisRaw("Mouse Y");
	currentRotation = Mathf.Clamp(currentRotation, minYRotation, maxYRotation);
	transform.Rotation = Quaternion.identity * Quaternion.AngleAxis(currentRotation, transform.right);
}

From this approach, the current Y rotation is maintained by a single float value and is sent through a rotation to determine a new facing angle. Adding the rotation to Quaternion.identity ensures that looking up and down will never exceed the limits placed on it.

In this specific example, the X axis will also need to be calculated manually in the same way, but there will likely be no need to clamp the values for it.

Just by the way here it’s explained well: