Help Rotating Camera Smoothly a set amount of degrees with Q and E inputs

Hi. I am a beginner. I have set a Cinemachine FreeLook camera on my top down view project. I want to smoothly rotate the camera around the X axis in 45 degree increments by using keyboard inputs Q and E . The code I attached to the camera works rotating the camera but it instantly increases to the set amount. I tried Mathf.SmoothDamp and SmoothDampAngle but i don’t understand how to make it work. I also tried increasing the Input Axis Value to a set amount and stopping it when reaching 45 degrees but could not make it work either.

Any help on implementing a smooth and accurate 45 degree movement will be appreciated.

This is the simple script i wrote:

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

public class CameraRotate : MonoBehaviour
{
    public CinemachineFreeLook vCam;

    [SerializeField] private int rotateAmount = 45;

    // Start is called before the first frame update
    void Start()
    {
        vCam = GetComponent<CinemachineFreeLook>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            RotateCameraRight();
        }
        else if (Input.GetKeyDown(KeyCode.E))
        {
            RotateCameraLeft();
        }
    }

    private void RotateCameraRight()
    {
        vCam.m_XAxis.Value += rotateAmount;
    }

    private void RotateCameraLeft()
    {
        vCam.m_XAxis.Value -= rotateAmount;
    }
}

I don’t see how you are using freelook for a top-down game. Could you share an image of your project or explaing why you are using freelook?

Hi.

Thanks for the reply. The reason I am using freelook its because as a beginner it was really easy to set up and use the TopRig, MidRig and and BottomRig to control view distance using the Mouse ScrollWheel. I was trying to achieve a camera system very similar to the one on the game Dont StarveTogether.

7623367--948181--Prototype screen 1.JPG 7623367--948184--Prototype screen 2.JPG 7623367--948187--Prototype screen 3.JPG

When a key is pressed, store the desired destination value as a member variable. In Update(), if the current value does not match the destination, modify it to approach the destination value. Eventually, it will reach the target value.

1 Like

I would use FramingTransposer in the Body for a game like that.

To position the camera, modify the X rotation value of the vcam (probably around ~70).
For zooming, you can modify the Framing Transposer’s Camera Distance parameter.
For accurate, 45 degree turns you can directly control the vcam’s Y rotation value.

Thank you so much for you reply. You got me to look at the problem in a different way than i was thinking and that led me to solve it. Like i said I am a beginner so i don’t know if i used the most effective or best way but it works. Thank you!

If anyone else is looking to solve this problem, this is how i did it.

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

public class FreeLookRotate : MonoBehaviour
{
    public CinemachineFreeLook vCam;

    [SerializeField] private float rotateAmount = 45;
    [SerializeField] private float transitionTime = .3f;
   
    private float initialPosition = 0;
    private float targetPosition = 0;
    private float t = 0f;

    private bool canMove = true;

    // Start is called before the first frame update
    void Start()
    {
        vCam = GetComponent<CinemachineFreeLook>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q) && canMove)
        {
            RotateCameraRight();
        }
        else if (Input.GetKeyDown(KeyCode.E) && canMove)
        {
            RotateCameraLeft();
        }

        if (initialPosition != targetPosition)
        {
            if (t > 1)
            {
                return;
            }
            t += Time.deltaTime / transitionTime;
            float newPosition = Mathf.SmoothStep(initialPosition, targetPosition, t);
            vCam.m_XAxis.Value = newPosition;
            if (targetPosition == vCam.m_XAxis.Value)
            {
                canMove = true;
            }
            else
            {
                canMove = false;
            }
        }
    }

    private void RotateCameraRight()
    {
        initialPosition = vCam.m_XAxis.Value;
        targetPosition = (initialPosition + rotateAmount);
        t = 0;
    }

    private void RotateCameraLeft()
    {
        initialPosition = vCam.m_XAxis.Value;
        targetPosition = (initialPosition - rotateAmount);
        t = 0;
    }
}
1 Like

You should build in some slush to account for floating point imprecision. Generally it’s not a good idea to do hard == on floats.

1 Like

Thanks. I’m self taught and have a career on something that has nothing to do with computers, so i spent a few minutes searching for terms like “Unity slush” and “C# slush” with no success but I finally went searching for how to compare floats and decided this was a simple solution for me. If you think there is a better way please let me know. I really appreciate the help!

using UnityEngine;
using Cinemachine;

public class FreeLookRotate : MonoBehaviour
{
    public CinemachineFreeLook vCam;

    [SerializeField] private float rotateAmount = 45;
    [SerializeField] private float transitionTime = .3f;
   
    [SerializeField] private float initialPosition = 0;
    [SerializeField] private float targetPosition = 0;
   
    private float t = 0f;
    private float slush = .005f;

    private bool canMove = true;

    // Start is called before the first frame update
    void Start()
    {
        vCam = GetComponent<CinemachineFreeLook>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q) && canMove)
        {
            RotateCameraRight();
        }
        else if (Input.GetKeyDown(KeyCode.E) && canMove)
        {
            RotateCameraLeft();
        }

        if (initialPosition != targetPosition)
        {
            if (t > 1)
            {
                return;
            }
            t += Time.deltaTime / transitionTime;
           
            float newPosition = Mathf.SmoothStep(initialPosition, targetPosition, t);
            vCam.m_XAxis.Value = newPosition;

            /*if (targetPosition == vCam.m_XAxis.Value)
            {
                canMove = true;
            }
            else
            {
                canMove = false;
            }*/
           
            if (vCam.m_XAxis.Value >= targetPosition - slush && vCam.m_XAxis.Value <= targetPosition + slush)
            {
                canMove = true;
            }
            else
            {
                canMove = false;
            }

        }
    }

    private void RotateCameraRight()
    {
        initialPosition = vCam.m_XAxis.Value;
        targetPosition = (initialPosition + rotateAmount);
        t = 0;
    }

    private void RotateCameraLeft()
    {
        initialPosition = vCam.m_XAxis.Value;
        targetPosition = (initialPosition - rotateAmount);
        t = 0;
    }
}

Gregory meant this :wink:

float tolerance = 0.0001f; // this value is arbitrary, adjust it for your precision needs
if (Math.Abs(a - b) < tolerance)
{
      // float a and b are equal (within tolerance of each other)
}

What you did is the same, but a bit longer. :slight_smile:

2 Likes

Thank you!