0
\$\begingroup\$

I completed a camera tutorial for Unity. I can rotate a camera around my figure around the Y axis (Vector3.up) and I wanted to extend that for a Fixed-Free 3rd Person camera (What are the types of 3rd-person camera called?) where I can tilt aswell but I am stuck with the wrong rotation.

I expect the camera to go up/down whenever I use the joystick up/down and always go left/right when I use the joystick left/right.

But instead of that I get always left/right movement as I wish but up/down is only working at the center. The further I go left or right (see images) the less I go up/down. This sounds super complicated, please see the images. I want the same behaviour as shown when the camera is behind the object and I want to avoid the behaviour at the right side like in the first image.

Bonus would be if I can limit the up and down movement to say 160° so the player can't look top down.

unwanted behaviour wanted behaviour no matter the y rotation

The Code looks like this (only RotateCamera() and UpdateCameraPosition() are relevant):

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

public class PlayerCamera : MonoBehaviour
{
    [System.Serializable]
    public class InputSettings : System.Object
    {
        public float inputThreshold = 0.1f;
        public string VERTICAL_AXIS = "CameraVertical";
        public string HORIZONTAL_AXIS = "CameraHorizontal";
        public string LOCK_TARGET_PYRAMID = "LockToPyramid";
        public string LOCK_TARGET_AREA = "LockToArea";
    }

    [SerializeField] private Transform target;
    [SerializeField] private float cameraSpeed = 2;
    [SerializeField] private Vector3 lookAtPlayerOffset = new Vector3(0f, 0.6f);

    private PlayerController playerController;
    private float cameraHorizontal, cameraVertical;
    private float lockPyramid, lockArea;
    private InputSettings inputSettings;
    private Vector3 cameraPlayerOffset;

    void Start()
    {
        SetCameraTarget(target);

        inputSettings = new InputSettings();
        cameraPlayerOffset = transform.position - playerController.transform.position;
    }

    private void Update()
    {
        GetInput();
    }

    private void LateUpdate()
    {
        RotateCamera();
        UpdateCameraPosition();
    }

    private void RotateCamera()
    {
        Quaternion cameraRotationXDelta = Quaternion.AngleAxis(cameraHorizontal * cameraSpeed, Vector3.up);
        Quaternion cameraRotationYDelta = Quaternion.AngleAxis(cameraVertical * cameraSpeed, Vector3.right);

        // this does not work how I wish it would after rotating around a bit
        cameraPlayerOffset = cameraRotationYDelta * cameraRotationXDelta * cameraPlayerOffset;

    }

    private void UpdateCameraPosition()
    {
        // prevent camera from clipping through floor
        Vector3 newPos = playerController.transform.position + cameraPlayerOffset;
        newPos.y = newPos.y < 0.2f ? newPos.y = 0.2f : newPos.y;
        transform.position = newPos;
        transform.LookAt(target.transform.position + lookAtPlayerOffset);
    }

    private void GetInput()
    {
        cameraHorizontal = Input.GetAxis(inputSettings.HORIZONTAL_AXIS); // interpolated
        cameraVertical = Input.GetAxis(inputSettings.VERTICAL_AXIS); // interpolated

        lockPyramid = Input.GetAxis(inputSettings.LOCK_TARGET_PYRAMID); // interpolated
        lockArea = Input.GetAxis(inputSettings.LOCK_TARGET_AREA); // interpolated
    }

    private void SetCameraTarget(Transform targetTransform)
    {
        target = targetTransform;

        if (target != null)
        {
            if (target.GetComponent<PlayerController>())
            {
                playerController = target.GetComponent<PlayerController>();
            }
            else
            {
                Debug.LogError("The camera's target needs a player character controller.");
            }
        }
        else
        {
            Debug.LogError("Your camera needs a target");
        }
    }
}
\$\endgroup\$
0
\$\begingroup\$

This line rotates the camera around the world X axis (Vector3.right):

Quaternion cameraRotationYDelta = Quaternion.AngleAxis(cameraVertical * cameraSpeed, Vector3.right);

So when your camera's offset from the character is close to perpendicular to the world X axis, you rotate in a wide circle around that axis when rotated by the line above.

As your camera offset direction swings toward the world X axis, it starts tracing out a narrower and narrower cone around that axis.

At the limit, when your camera is directly to the left or right of your character, this rotation produces no change in position at all: points on the rotation axis remain fixed no matter how great the angle of rotation.

Instead, you probably want to rotate about the camera's X axis (transform.right). This ensures the rotation axis runs left-right relative to what the player sees on screen in the current camera orientation, rather than with regard to the fixed world coordinate system.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.