How to limit rotation of camera around an object along X axis?

Hello,
i have a tank and a camera as child of a game object that let me follow exactly both the tank and the rotation of the turret.
With the following code i managed to rotate the camera up and down as i want to, but i can’t find a solution about limitating the rotation between 85 and 10 degrees along X axis. Can you help me pls. Here is the code:

public class CameraFollow : MonoBehaviour
{
    #region Variables
   
    public Transform target;
    public float rotationSpeed = 45.0f;
    [Header("Limits")]
    public float maxRotation = 85.0f;
    public float initRotation = 10.0f;
    public float minRotation = 5.0f;
    public float offset = 5.0f;
    [Header("Positions")]
    public Vector3 currentRotation = Vector3.zero;
    public Vector3 maxHeight = new Vector3(0, 20, 0);
    public Vector3 initPosition;
    public Vector3 endPos = new Vector3(0, 20, 0);

    private float angle;
    private bool up = false;
    private bool down = false;
    
    #endregion

    #region Built-in Methods
    private void Start()
    {
        transform.localEulerAngles = currentRotation;
    }
    private void Update()
    {
        if (target != null)
        {
            transform.LookAt(target);
            RotateCamera();
        }
        
    }

    private void FixedUpdate()
    {
        if (up is true)
        {
            transform.Translate(Vector3.up * rotationSpeed * Time.deltaTime);
            //transform.RotateAround(target.localPosition, Vector3.right, rotationSpeed * Time.deltaTime);
            CapAngle();
        }
        else if (down is true)
        {
            transform.Translate(Vector3.down * rotationSpeed * Time.deltaTime);
            //transform.RotateAround(target.localPosition, Vector3.left, rotationSpeed * Time.deltaTime);
            CapAngle();
        }
        else
            transform.Rotate(Vector3.right, 0f);
   }

    //Here i want to add limits of rotations
    void CapAngle()
    {
        currentRotation = UnityEditor.TransformUtils.GetInspectorRotation(transform);
        currentRotation.x = Mathf.Clamp(currentRotation.x, minRotation, maxRotation);
        transform.localEulerAngles = currentRotation;
    }

    public void RotateUp()
    {
        up = true;
    }

    public void RotateDown()
    {
        down = true;
    }

    public void RotateStop()
    {
        up = false;
        down = false;
    }

    public void RotateCamera()
    {
        RotateStop();

        if (Input.GetKey(KeyCode.Q))
            RotateDown();
        
        else if (Input.GetKey(KeyCode.E))
            RotateUp();  
    }
#endregion

EDIT: As i said in the comments to JasonBennett let me suggest you to see this link: [R. I. P.] Tanki X Gameplay || "A forgotten turret" - YouTube

Pay particular attention from 1:50 to 2:09 and from 2:17 to 2:31 circa about vertical movements of the camera. Those are done by pressing only Q/E keys. I want to reproduce that camera behaviour. So to clarify: - the gun of the turret will not move upwards and downwards like real tanks, the rotating part is the turret; - at the moment i prefer to play only with keyboard controls (i would like to add the code for mouse controls feature later).

EDIT: Here is a link of an image explaining what i want to create Imgur: The magic of the Internet

Thanks for the suggestions @JasonBennett , let me suggest you to see this link: [R. I. P.] Tanki X Gameplay || "A forgotten turret" - YouTube

Pay particular attention from 1:50 to 2:09 and from 2:17 to 2:31 ca. about vertical movements of the camera. Those are done by pressing only Q/E keys.
I want to reproduce that camera behaviour.
So to clarify:

  • the gun of the turret will not move upwards and downwards like real tanks, the rotating part is the turret;
  • at the moment i prefer to play only with keyboard controls (most probably later i’ll add the code for mouse controls)

use a clamp; here’s a Brackeys tutorial skip to the part with the clamp.

UPDATE: I created this new script that let me made it:

public class ControlCamera : MonoBehaviour
{
    public Transform target;//the target object
    public Vector3 CameraPosition; //this vector holds ONLY the Y coord of the camera
    [Header("Limits")]
    //These are arbitrary values, you can set them according to preference
    public float minY = 2;
    public float maxY = 11; 
    public float speedMod = 45.0f;//a speed modifier

    private Vector3 point;//the coord to the point where the camera looks at
    public bool up = false; //can the camera go up?
    public bool down = false; //can the camera go down?

    void Start()
    {//Set up things on the start method
        point = target.transform.position;//get target's coords
        transform.LookAt(point);//makes the camera look to it
        CheckPosition();
    }

    void FixedUpdate()
    {//makes the camera rotate around "point" coords, rotating around its X axis, 20 degrees per second times the speed modifier

        CheckPosition();
        if (Input.GetKey(KeyCode.E) && up is true)
        {
            transform.RotateAround(target.transform.position, target.right, speedMod * Time.deltaTime);
        }

        else if (Input.GetKey(KeyCode.Q) && down is true)
        {
            transform.RotateAround(target.transform.position, target.right, -speedMod * Time.deltaTime);
        }        
    }

    void CheckPosition()
    {
        //Get the camera Y axis position in the turret's local space
        CameraPosition.y = target.InverseTransformPoint(transform.position).y;
        
        //If CameraPosition.y is over the limits, trigger up/down
        down = (CameraPosition.y < minY) ? false : true;
        up = (CameraPosition.y > maxY) ? false : true;
    }
}

I changed the lookAt(target)-Translate() system to RotateAround() method and used target.right vector to let the camera rotate locally around the target and not globally. Thanks again for your suggestions guys :slight_smile:

So based on the conversation we had in the comments to your original post, it looks like you are not actually rotating the camera, but are instead moving it up and down using transform.Translate() while having it LookAt(target) where target is your tank’s turret. This is slightly different from rotation in that your camera is moving in a straight line up or down while looking at the turret instead of moving in an arc around the turret. I will show you how to do it both ways so you can see the difference.

Way #1: Using transform.Translate() as you have been

The easiest way is to set a limit in the Y axis movement (not rotation) of the camera based on its position relative to the turret.

//Get the camera Y axis position in the turret's local space

float yPositionInTurretSpace = target.InverseTransformPoint(transform.position).y;

float minY = 0;
float maxY = 4; //These are arbitrary values, you can set them according to preference

bool canMoveUp;
bool canMoveDown;

if (yPositionInTurretSpace < minY)
	canMoveDown = false;
else 
	canMoveDown = true;

if (yPositionInTurretSpace > maxY)
	canMoveUp = false;
else
	canMoveUp = true;

if (up && canMoveUp)
	transform.Translate(Vector3.up * rotationSpeed * Time.deltaTime);

if (down && canMoveDown)
	transform.Translate(Vector3.down * rotationSpeed * Time.deltaTime);

Alternatively for cleanliness you can simplify the if() statements using the conditional operator:

canMoveDown = (yPositionInTurretSpace < minY) ? false : true;
canMoveUp = (yPositionInTurretSpace > maxY) ? false : true;

You could figure out maxY and minY using trigonometry to match the angles you want to use, but honestly it’s just easier to play around with the arbitrary values to see if you can get the effect you want.

Way #2: Using RotateAround()

//Get vectors to compare

Vector3 turretVector = -target.transform.front; //the "back" vector of the turret
Vector3 cameraVector = transform.position - target.transform.position //this vector points from the turret to the camera

float angleBetweenTurretAndCamera = Vector3.Angle(turretVector, cameraVector);

float maxAngle = 85;
float minAngle = 5;

bool canRotateUp;
bool canRotateDown;

canRotateUp = (angleBetweenTurretAndCamera < maxAngle) ? true : false;
canRotateDown = (angleBetweenTurretAndCamera > minAngle) ? true : false;

if (canRotateUp && up)
{
	//Notice that we use the turret's right axis instead of Vector3.right so that you properly follow the turret even if the tank is on a hill
	transform.RotateAround(target.localPosition, target.transform.right, rotationSpeed * Time.deltaTime);	
}
if (canRotateDown && down)
{
	transform.RotateAround(target.localPosition, target.transform.right, -rotationSpeed * Time.deltaTime);	
}

Let me know if this works for you or if you have any questions!

-Jason

References:

https://docs.unity3d.com/Manual/DirectionDistanceFromOneObjectToAnother.html