Using a button to control the freelook camera

I have taken the beginner course and some of the RPG course but when it comes to this cinemachine and using the events, I am very confused with this course and i do not know why?

Anyway I would like to use the right mouse buttton down to control the freelook camera otherwise the camera just follow the player. I did try to understand how another student came across the soloution but as it was vague, and Im not understanding how its working. I just need a little help with this, if someone could help or atleast point me in the best direction would be appreiceted.

With the Freelook camera, this is likely to be impossible (as the freelook camera is quite literally designed to work the way it does by Cinemachine).
Can you link to the post you found where a student had done it? Then I can see if that’s a good approach or if another needs to be crafted.

Hi brian, If anyone can work out the best approach I know you can.
https://community.gamedev.tv/t/cinemachineinputprovider-onmouseclick/213933/4

Is there another cinemachine camera to use if that would be the best approach? Basically i want to be able to just have a follow cam unless, I hold in right mouse where i can look about then it snaps back to behind the player, or slowly pans back if that makes sense.

I’ll share the approach I used in a work in progress game. Since you’re not interested in the FreelookCamera, a straight virtual camera will work better for what we’re doing.
Make the VirtualCamera follow and lookat the player, set the Body to Framing Transposer and the Aim at Do Nothing. Adjust the camera as needed to be in the correct position.

Here is my original FollowCameraZoomAndRotate script I use in SpellbourneHunter. I’ll paste the original script, and then I’ll make the changes that should adapt it to be used with the InputReader.

FollowCameraZoomAndRotate
using Cinemachine;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;

namespace TkrainDesigns.Cinematics
{
    [RequireComponent(typeof(CinemachineVirtualCamera))]
    public class FollowCameraZoomAndRotate : MonoBehaviour
    {
        [SerializeField] private float zoomSensitivity = 1.0f;
        [SerializeField] private float minimumZoom = 5;
        [SerializeField] private float maximumZoom = 20;
        [SerializeField] private float zoomSpeed = 5;
        [SerializeField] private float turnSensitivity = .1f;

        CinemachineFramingTransposer transposer;

        private void Awake()
        {
            CinemachineVirtualCamera cam = GetComponent<CinemachineVirtualCamera>();
            transposer = cam.GetCinemachineComponent<CinemachineFramingTransposer>();
        }

        private float currentZoom = 10;

        private float desiredZoom = 10;

        private float currentRotation = 0;
        private float desiredRotation = 0;
        private float wheelValue;

        // Called by new input system.  
        public void OnScrollWheelTurn(InputAction.CallbackContext context)
        {
            if (EventSystem.current.IsPointerOverGameObject()) return;
            wheelValue = context.ReadValue<float>();
            desiredZoom -= context.ReadValue<float>() * zoomSensitivity;
            desiredZoom = Mathf.Clamp(desiredZoom, minimumZoom, maximumZoom);
        }

        private bool rotatePressed = false;
        private Vector2 lastFrameMousePosition;

        // called by new input system.  
        public void OnRotateButtonPressed(InputAction.CallbackContext context)
        {
            if (EventSystem.current.IsPointerOverGameObject()) return;
            bool currentRotationPressed = context.ReadValueAsButton();
            if (currentRotationPressed && !rotatePressed)
            {
                lastFrameMousePosition = Mouse.current.position.ReadValue();
            }

            rotatePressed = currentRotationPressed;
        }


        private void Update()
        {
            Rect screen = new Rect(0, 0, Screen.width, Screen.height);
            if (!screen.Contains(Mouse.current.position.ReadValue()))
            {
                return;
            }

            currentZoom = Mathf.Lerp(currentZoom, desiredZoom, Time.deltaTime * zoomSpeed);
            transposer.m_CameraDistance = currentZoom;
            if (rotatePressed)
            {
                ManageRotation();
            }
        }


        private void ManageRotation()
        {
            Vector2 currentPosition = Mouse.current.position.ReadValue();
            Vector2 deltaVector2 = currentPosition - lastFrameMousePosition;

            float delta = 0;

            if (Mathf.Abs(deltaVector2.x) > Mathf.Abs(deltaVector2.y))
            {
                delta = lastFrameMousePosition.y > Screen.height / 2.0f ? -deltaVector2.x : deltaVector2.x;
            }
            else
            {
                delta = lastFrameMousePosition.x < Screen.width / 2.0f ? -deltaVector2.y : deltaVector2.y;
            }

            lastFrameMousePosition = currentPosition;

            desiredRotation += (delta * turnSensitivity * Time.deltaTime);
            currentRotation = Mathf.Lerp(currentRotation, desiredRotation, Time.deltaTime * zoomSpeed);
            Vector3 eulers = transform.eulerAngles;
            eulers.y = currentRotation;
            transform.eulerAngles = eulers;
        }
    }
}

There is a lot to this, but it’s predicated on a different style of handling the input, rather than an InputHandler as we use in this course, we put a built in PlayerInput component on the core and use UnityEvents to call the methods.

Since we’re already using an InputHandler script, we’ll keep the calls in the InputHandler and set our CameraZoom script to grab the data from the InputHandler.

Let’s start with the changes to Controls, although if you don’t wish to have the zoom, you only need to add a Turn action as a Button, set to the Right Mouse. If you want the optional Zoom, then add a Zoom action of type Axis to the Controls, and bind it to the mouse Scroll.

In InputHandler, you’ll need to add the handler for Zoom. I made a pulbic Vector2 ScrollValue {get; private set;} and the handler itself is the same as our Look handler, setting the value of ScrollValue to the context.ReadValue<float>();

Next, we need to get hold of the InputReader from our FollowCameraZoomAndRotate script.
Add a field for the input reader

private InputReader inputReader;

and in Awake, add

inputReader = GameObject.FindWithTag("Player").GetComponent<InputReader>();

Replace the OnScrollWheelTurn and OnRotateButtonPressed with these methods:

        public void CheckScrollWheel()
        {
            if (EventSystem.current.IsPointerOverGameObject()) return;
            wheelValue = inputReader.ScrollValue;
            desiredZoom -= wheelValue * zoomSensitivity;
            desiredZoom = Mathf.Clamp(desiredZoom, minimumZoom, maximumZoom);
        }

        public void CheckRotation()
        {
            if (EventSystem.current.IsPointerOverGameObject()) return;
            bool currentRotationPressed = inputReader.CameraTurn;
            if (currentRotationPressed && !rotatePressed)
            {
                lastFrameMousePosition = Mouse.current.position.ReadValue();
            }
            rotatePressed = currentRotationPressed;
        }

And finally, call these two methods in Update().

Here’s the final script:

FollowCameraZoomAndRotate.cs revised
using Cinemachine;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;


namespace TkrainDesigns.Cinematics
{
    [RequireComponent(typeof(CinemachineVirtualCamera))]
    public class FollowCameraZoomAndRotate : MonoBehaviour
    {
        [SerializeField] private float zoomSensitivity = 1.0f;
        [SerializeField] private float minimumZoom = 5;
        [SerializeField] private float maximumZoom = 20;
        [SerializeField] private float zoomSpeed = 5;
        [SerializeField] private float turnSensitivity = .1f;

        CinemachineFramingTransposer transposer;
        private InputReader inputReader;
        private void Awake()
        {
            CinemachineVirtualCamera cam = GetComponent<CinemachineVirtualCamera>();
            transposer = cam.GetCinemachineComponent<CinemachineFramingTransposer>();
            inputReader = GameObject.FindWithTag("Player").GetComponent<InputReader>();
        }

        private float currentZoom = 10;

        private float desiredZoom = 10;

        private float currentRotation = 0;
        private float desiredRotation = 0;
        private float wheelValue;

        
        public void CheckScrollWheel()
        {
            if (EventSystem.current.IsPointerOverGameObject()) return;
            wheelValue = inputReader.ScrollValue;
            desiredZoom -= wheelValue * zoomSensitivity;
            desiredZoom = Mathf.Clamp(desiredZoom, minimumZoom, maximumZoom);
        }

        private bool rotatePressed = false;
        private Vector2 lastFrameMousePosition;

        
        public void CheckRotation()
        {
            if (EventSystem.current.IsPointerOverGameObject()) return;
            bool currentRotationPressed = inputReader.CameraTurn;
            if (currentRotationPressed && !rotatePressed)
            {
                lastFrameMousePosition = Mouse.current.position.ReadValue();
            }
            rotatePressed = currentRotationPressed;
        }


        private void Update()
        {
            CheckRotation();
            CheckScrollWheel();
            Rect screen = new Rect(0, 0, Screen.width, Screen.height);
            if (!screen.Contains(Mouse.current.position.ReadValue()))
            {
                return;
            }

            currentZoom = Mathf.Lerp(currentZoom, desiredZoom, Time.deltaTime * zoomSpeed);
            transposer.m_CameraDistance = currentZoom;
            if (rotatePressed)
            {
                ManageRotation();
            }
        }


        private void ManageRotation()
        {
            Vector2 currentPosition = Mouse.current.position.ReadValue();
            Vector2 deltaVector2 = currentPosition - lastFrameMousePosition;

            float delta = 0;

            if (Mathf.Abs(deltaVector2.x) > Mathf.Abs(deltaVector2.y))
            {
                delta = lastFrameMousePosition.y > Screen.height / 2.0f ? -deltaVector2.x : deltaVector2.x;
            }
            else
            {
                delta = lastFrameMousePosition.x < Screen.width / 2.0f ? -deltaVector2.y : deltaVector2.y;
            }

            lastFrameMousePosition = currentPosition;

            desiredRotation += (delta * turnSensitivity * Time.deltaTime);
            currentRotation = Mathf.Lerp(currentRotation, desiredRotation, Time.deltaTime * zoomSpeed);
            Vector3 eulers = transform.eulerAngles;
            eulers.y = currentRotation;
            transform.eulerAngles = eulers;
        }
    }
}

The final script should go on your Virtual Camera.
At the moment, this script doesn’t return to a “behind” state after a few seconds, I’m out of time for the evening.

1 Like

Thank you once again brain, you always explain in give very in-depth responses to help my learning journey. with this information, as I understand a bit more on how to handle this I should be able to make the camera return to a “behind” state with the other docs out there.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms