- Home /
Third-person camera snaps to 270 degrees on activation
I'm writing a third-person camera that usually trails behind the player, but pans in response to player input when they hold right click. The camera control script reads as follows:
public Collider target;
// The player's gameobject - we want to look at this
new public Camera camera;
// The main camera - the script should move and rotate this
public float rotationUpdateSpeed = 60.0f,
verticalRotationSpeed = 20.0f,
followUpdateSpeed = 10.0f;
// Variables to fine-tune camera performance
private float optimalDistance;
//How far the camera should be from the player
private float mouseX;
private float mouseY;
//Store the GetAxis of the mouse in order to aim the camera
Quaternion cameraRotation;
Vector3 cameraPosition;
void Start (){
optimalDistance = (camera.transform.position - target.transform.position).magnitude;
}
void Update (){
if (Input.GetMouseButtonUp (1)) {
mouseX = target.transform.rotation.z;
mouseY = target.transform.rotation.y;
}
}
void LateUpdate ()
{
if (Input.GetMouseButton (1)) {
FreeUpdate ();
}
else {
FollowUpdate();
}
//Screen.lockCursor = true;
}
void FollowUpdate (){
// Camera follows behind the player
Vector3 cameraForward = target.transform.position - camera.transform.position;
cameraForward = new Vector3 (cameraForward.x, 0.0f, cameraForward.z);
float rotationAmount = Vector3.Angle (cameraForward, target.transform.forward);
rotationAmount *= followUpdateSpeed * Time.deltaTime;
if (Vector3.Angle (cameraForward, target.transform.right) < Vector3.Angle (cameraForward, target.transform.right * -1.0f)){
// Rotate to the left if the camera is to the right of target forward
rotationAmount *= -1.0f;
}
camera.transform.RotateAround (target.transform.position, Vector3.up, rotationAmount);
}
void FreeUpdate (){
//Camera controlled by mouse
mouseX += Input.GetAxis("Mouse X") * rotationUpdateSpeed * 0.02f;
mouseY -= Input.GetAxis("Mouse Y") * verticalRotationSpeed * 0.02f;
cameraRotation= Quaternion.Euler(mouseY, mouseX, 0f);
cameraPosition= cameraRotation* new Vector3(0.0f, 2.0f, -optimalDistance) + target.transform.position;
camera.transform.rotation = cameraRotation;
camera.transform.position = cameraPosition;
}
This works perfectly, except whenever I first click the right mouse button to active mouselook, instead of remaining behind the player until the mouse is moved, the camera.transform.rotation snaps to 270, so it's looking at the player's side. It pans correctly, and snaps back behind the player once I release the right button, but every time I turn mouselook on it begins by snapping back to 270 degrees rotation. How can I fix this so the camera starts behind the player (in its follow position) every time I right click to start mouselook?
Answer by EvilWarren · May 19, 2014 at 11:07 AM
Your issue is the line:
cameraRotation= Quaternion.Euler(mouseY, mouseX, 0f);
This orientation probably looks at the side of your character. This rotation is global and is not relative to the position of character/player.
Try modifying it to take the last known rotation of the camera like this:
public Collider target;
// The player's gameobject - we want to look at this
new public Camera camera;
// The main camera - the script should move and rotate this
public float rotationUpdateSpeed = 60.0f,
verticalRotationSpeed = 20.0f,
followUpdateSpeed = 10.0f;
// Variables to fine-tune camera performance
private float optimalDistance;
//How far the camera should be from the player
private float mouseX;
private float mouseY;
//Store the GetAxis of the mouse in order to aim the camera
private Vector3 lastCameraRotationEuler;
Quaternion cameraRotation;
Vector3 cameraPosition;
void Start (){
optimalDistance = (camera.transform.position - target.transform.position).magnitude;
}
void Update (){
if (Input.GetMouseButtonUp (1)) {
mouseX = target.transform.rotation.z;
mouseY = target.transform.rotation.y;
}
}
void LateUpdate ()
{
if (Input.GetMouseButton (1)) {
FreeUpdate ();
}
else {
FollowUpdate();
}
//Screen.lockCursor = true;
}
void FollowUpdate (){
// Camera follows behind the player
Vector3 cameraForward = target.transform.position - camera.transform.position;
cameraForward = new Vector3 (cameraForward.x, 0.0f, cameraForward.z);
float rotationAmount = Vector3.Angle (cameraForward, target.transform.forward);
rotationAmount *= followUpdateSpeed * Time.deltaTime;
if (Vector3.Angle (cameraForward, target.transform.right) < Vector3.Angle (cameraForward, target.transform.right * -1.0f)){
// Rotate to the left if the camera is to the right of target forward
rotationAmount *= -1.0f;
}
camera.transform.RotateAround (target.transform.position, Vector3.up, rotationAmount);
lastCameraRotationEuler = camera.transform.rotation.eulerAngles;
}
void FreeUpdate (){
//Camera controlled by mouse
mouseX += Input.GetAxis("Mouse X") * rotationUpdateSpeed * 0.02f;
mouseY -= Input.GetAxis("Mouse Y") * verticalRotationSpeed * 0.02f;
cameraRotation= Quaternion.Euler(lastCameraRotationEuler.x+ mouseY, lastCameraRotationEuler.y+mouseX, lastCameraRotationEuler.z);
cameraPosition= cameraRotation* new Vector3(0.0f, 2.0f, -optimalDistance) + target.transform.position;
camera.transform.rotation = cameraRotation;
camera.transform.position = cameraPosition;
}
Just three extra lines to add using another Vector3 that stores the last camera position from the FollowUpdate() method. Just do a find for lastCameraRotationEuler in the code if you are unsure which lines are new.
Holy cow that works perfectly, you sir are a scholar and a gentleman! Thank you very much for the help, having a camera that works is a glorious thing ^_^