Search code examples
c#unity-game-enginecamera

First click on the screen changes camera position and angle at the object


In the given script the camera is set in a certain position at the start of the game. To adjust the view, I must use mouse-drag. However, the first click on the screen the camera position and angle slightly changes.

public class CameraOrbit : MonoBehaviour
{
    public Camera cam;
    public Transform target;
    public float radius = 10;
    private Vector3 currentPosition;

    public Vector3 positionPreOffset;
    public Vector3 rotationPreOffset;

    private void Start()
    {
        // Calculate the initial camera position based on target, position offset, and rotation offset.
        Vector3 desiredPosition = target.position + target.rotation * positionPreOffset;
        cam.transform.position = desiredPosition;

        Quaternion desiredRotation = target.rotation * Quaternion.Euler(rotationPreOffset);
        cam.transform.rotation = desiredRotation;

        // Store the current camera position and calculate the radius.
        currentPosition = cam.transform.position;
        radius = currentPosition.magnitude;
    }

    private void LateUpdate()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // Store the current mouse position when the left mouse button is clicked.
            currentPosition = cam.ScreenToViewportPoint(Input.mousePosition);
        }
        else if (Input.GetMouseButton(0))
        {
            // Calculate the new mouse position.
            Vector3 newPosition = cam.ScreenToViewportPoint(Input.mousePosition);

            // Calculate the direction of mouse movement.
            Vector3 direction = currentPosition - newPosition;

            // Calculate rotation angles based on mouse movement.
            float rotationYAxis = -direction.x * 90;
            float rotationXAxis = direction.y * 90;

            // Reset the camera's position to the target's position.
            cam.transform.position = target.transform.position;

            // Apply the calculated rotations to the camera's rotation.
            cam.transform.rotation *= Quaternion.Euler(rotXaxis, rotYaxis, 0);
            cam.transform.Translate (new Vector3(0, 0, -radius));

            currentPosition = newPosition;
        }

I would like if camera's position wouldn't change at the first mouse click on the screen and maintain its position and angle before I'm adjusting/changing view.


Solution

  • You completely ignore the previous applied positionPreOffset and rotationPreOffset.

    Why don't you simply use Transform.RotateAround:

    private void LateUpdate()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // Store the current mouse position when the left mouse button is clicked.
            currentPosition = cam.ScreenToViewportPoint(Input.mousePosition);
        }
        else if (Input.GetMouseButton(0))
        {
            // Calculate the new mouse position.
            var newPosition = cam.ScreenToViewportPoint(Input.mousePosition);
    
            // Calculate the direction of mouse movement.
            var direction = currentPosition - newPosition;
    
            // Calculate rotation angles based on mouse movement.
            var rotationYAxis = -direction.x * 90;
            var rotationXAxis = direction.y * 90;
    
            cam.transform.RotateAround(target.position, Vector3.up, rotationYAxis);
            cam.transform.RotateAround(target.position, cam.transform.right, rotationXAxis);
    
            currentPosition = newPosition;
        }
    }
    

    which btw also fixes your issue with doing both rotations in local space while this now correctly rotates on the global Y axis

    For the typical orbit camera next steps will be:

    • track and clamp X rotation so you can not exceed +/- 90° or even less depending on your use case

      For this you can simply sum up the value of rotationXAxis and then only actually execute the rotation using an amount that does not exceed the allowed range

    • add zoom

      Quite trivial: Simply move the camera towards or away from the pivot point.

    • clamp zoom

      As before you keep track of your current distance to the pivot and limit our zoom to respect the limitations