Rotating camera script jumps to point near player before rotating


After a few attempts to find/write a script that would allow my camera to rotate around the player when the right mouse button’s held, I’ve got something that nearly works. The only problem is that the vector math for the script uses Vector3.forward as a baseline, and so whenever the right mouse button’s clicked, the camera jumps to a point that’s (0,0,1) away from the player (but then allows rotation correctly).

I’ve tried adjusting the script so that it uses -player.transform.forward as the baseline instead (thinking it would make it so that the camera always starts from just behind the player instead, which feels more natural), but the vector math being used here seems to only work properly when Vector3.forward is used, and when I change to my alternative idea, the camera can only rotate horizontally and cannot move vertically - I assume that’s because the math was made to work on Vector3.forward only.

I feel like I’m really close with this but vector math isn’t my strong suit and I don’t know how to make the camera use its current position (or the player’s current orientation) as a baseline for the rotation calculations rather than jumping to 1 unit away from the player each time the RMB is clicked.

Here’s a quick 30 second video showing the issue: Screen Recording 2022-09-06...

Here’s the code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class CameraController : MonoBehaviour
    public GameObject player;
    private float angleX, angleY;
    private float movementX, movementY;
    public float radius = 10;
    public bool rclick = false;

    // OnLook is triggered by a Look binding on the camera's InputSystem and fetches
    // delta values for X and Y mouse movement
    void OnLook(InputValue movementValue)
        Vector2 movementVector = movementValue.Get<Vector2>();
        movementX = movementVector.x;
        movementY = movementVector.y;

    void LateUpdate()
        // The below line is example code found from a tutorial. The code works to allow smooth
        // camera rotation over both axes, but because it starts with (0,0,1) in world space as
        // a baseline, when right-click is held the camera will always jump to be 1 unit away
        // from the player on the global Z axis before allowing free movement
        Vector3 orbit = Vector3.forward * radius;

        // The commented line below shows what I have tried to replace it with (so the origin
        // point is always just behind the player) but this somehow breaks the vertical rotation
        // and the character can only rotate horizontally when in use
        //Vector3 orbit = -player.transform.forward * radius;

        Debug.Log("orbit x: " + orbit.x + " | y: " + orbit.y + " | z :" + orbit.z);

        // rclick is set by the player's InputSystem when RMB is held - can be set as true for
        // testing purposes so the camera always follows the mouse
        if (rclick)
            angleX += movementX;
            angleY = Mathf.Clamp(angleY += movementY, -89, 0);

            // keeping horizontal rotation within 360 degrees
            if (angleX > 360)
                angleX -= 360;
            else if (angleX < 0)
                angleX += 360;
            orbit = Quaternion.Euler(angleY, angleX, 0) * orbit;
            transform.position = Vector3.Lerp(transform.position, player.transform.position + orbit, 0.2f);
        else // if right click is not held, return camera to just behind the player
            Vector3 defaultOrbit = player.transform.position + (player.transform.forward * -2) + player.transform.up;
            transform.position = Vector3.Lerp(transform.position, defaultOrbit, 0.01f);

Update: I’ve figured out something I’m probably going to keep using here. It’s a bit weird to my eyes but it’s working. Happy to clarify what I did if someone needs, but I no longer need an answer to this (I think).

I had a similar situation happen multiple times, and my most recent code looks like this:

spellCastPos = trans.position + breastHeight + (trans.forward / 2);

The “meat and potatoes” of this being the transform.forward divided by a number. Which allows you to keep the offset while rotating. Since a normal Vector3 offset doesn’t rotate properly when you modify the Z coordinate.

In my case I only needed to cut the value in half, but you’ll have to play with the division fraction to find the perfect float you’re looking for(maybe multiplying instead of dividing), as the math tends to be very weird. It’s not perfectly scalable. But once you find the right fraction, or math to suit your needs, all should be well. :slight_smile: