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
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).
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)
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
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:
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!