Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Rotating camera smoothly to set positions using Quaternions

Discussion in 'Scripting' started by IAmScoops, Jun 28, 2023.

  1. IAmScoops

    IAmScoops

    Joined:
    May 16, 2021
    Posts:
    9
    I've successfully scripted the camera in my game so that it rotates around the player looking at them from an overhead angle using this code:

    Code (CSharp):
    1. public class CameraFollow : MonoBehaviour
    2. {
    3.     public float turnSpeed = 4.0f;
    4.     public Transform player;
    5.    
    6.     public Vector3 offset;
    7.     private float rotate;
    8.  
    9.  
    10.     void Start(){
    11.         offset = new Vector3(0, 45, -45);
    12.     }
    13.  
    14.     void Update(){
    15.  
    16.  
    17.         if (Input.GetKeyDown(KeyCode.E)){
    18.             rotate += 0.4f;
    19.         }
    20.         if (Input.GetKeyUp(KeyCode.E)){
    21.             rotate += -0.4f;
    22.         }
    23.         if (Input.GetKeyDown(KeyCode.Q)){
    24.             rotate += -0.4f;
    25.         }
    26.         if (Input.GetKeyUp(KeyCode.Q)){
    27.             rotate += 0.4f;
    28.         }
    29.  
    30.  
    31.         offset = Quaternion.AngleAxis(rotate * turnSpeed, Vector3.up) * offset;
    32.         transform.position = player.position + offset;
    33.         transform.LookAt(player.position);
    34.  
    35.  
    36.     }
    37. }

    This code works flawlessly to use Q and E to rotate the camera smoothly and freely (controls will be revamped much later.

    However, next I want to add buttons that rotate the camera 45* at a time, which I did so with this code added in the void Update() below the other code


    Code (CSharp):
    1.         if (Input.GetKeyDown(KeyCode.J))
    2.         {
    3.             offset = Quaternion.AngleAxis(45, Vector3.up) * offset;
    4.         }
    5.         if (Input.GetKeyUp(KeyCode.K))
    6.         {
    7.             offset = Quaternion.AngleAxis(-45, Vector3.up) * offset;
    8.         }
    This code works... fine, but while it does successfully rotate the camera 45 degrees, I would much prefer if I could:
    A) Rotate the camera to set positions, I.E, rotate the camera to the *nearest* 45 degree angle (0, 45, 90, 135, 180, 225, 270, 315)
    B) Rotate the camera smoothly rather than SNAP to the angle
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    Camera stuff is pretty tricky... you may wish to consider using Cinemachine from the Unity Package Manager.

    There's even a dedicated forum: https://forum.unity.com/forums/cinemachine.136/

    Otherwise, here is how to smoothly change values over time:

    Smoothing movement between any two particular values:

    https://forum.unity.com/threads/beginner-need-help-with-smoothdamp.988959/#post-6430100

    You have currentQuantity and desiredQuantity.
    - only set desiredQuantity
    - the code always moves currentQuantity towards desiredQuantity
    - read currentQuantity for the smoothed value

    Works for floats, Vectors, Colors, Quaternions, anything continuous or lerp-able.

    The code: https://gist.github.com/kurtdekker/fb3c33ec6911a1d9bfcb23e9f62adac4
     
    IAmScoops likes this.
  3. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    510
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ThirdPersonCamera : MonoBehaviour
    6. {
    7. Vector3 angle;
    8.  
    9. public Transform player;
    10. Vector3 offset;
    11.  
    12.     void Start()
    13.     {
    14.     }
    15.  
    16.     void Update()
    17.     {
    18.         if (Input.GetKey(KeyCode.A))
    19.             angle.y+=5;
    20.         else if (Input.GetKey(KeyCode.D))
    21.             angle.y-=5;
    22.  
    23.         if (Input.GetKeyDown(KeyCode.W))
    24.             angle.x+=45;
    25.         else if (Input.GetKeyDown(KeyCode.S))
    26.             angle.x-=45;
    27.  
    28.         offset=new Vector3(0,0,-10);
    29.         offset=Quaternion.Euler(angle.x,angle.y,0)*offset;
    30.  
    31.         transform.position = Vector3.Slerp(transform.position, player.position+offset, 3.0f*Time.deltaTime);
    32.         transform.LookAt(player.position);
    33.     }
    34. }
     
  4. IAmScoops

    IAmScoops

    Joined:
    May 16, 2021
    Posts:
    9
    I've looked into Cinemachine, but for what I'm hoping to accomplish for my game, it might be a bit heavier weight than what I need, in theory if I can get this last feature to work, that's all I'd need for my playable camera for now, Even this 45* snapping feature is a bonus I wanted to add for user comfort and not strictly necessary.
     
  5. IAmScoops

    IAmScoops

    Joined:
    May 16, 2021
    Posts:
    9
    Sorry, this isn't even remotely what I'm trying to do with my camera. The camera has a locked Y position, and then rotates in a large circle (using Q and E) around my player looking down on them, while following their movements.


    Here's my current movement in action. Now all I'm trying to add are two buttons that rotate the camera to the nearest 45* angle (clockwise or counterclockwise depending on input), smoothly. The last block of code I included in my original post snaps the camera by 45* regardless of the current position, which isn't quite what I'm looking for.
     
  6. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    510
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ThirdPersonCamera : MonoBehaviour
    6. {
    7. Vector3 angle;
    8. public Transform player;
    9. Vector3 offset;
    10.  
    11.     void Start()
    12.     {
    13.     }
    14.  
    15.     void Update()
    16.     {
    17.         if (Input.GetKey(KeyCode.Q))
    18.             angle.y+=2;
    19.         else if (Input.GetKey(KeyCode.E))
    20.             angle.y-=2;
    21.  
    22.         if (Input.GetKeyDown(KeyCode.J))
    23.         {
    24.             angle.y+=45;
    25.             angle.y=Mathf.Round(angle.y/45)*45;
    26.         }
    27.         else if (Input.GetKeyDown(KeyCode.K))
    28.         {
    29.             angle.y-=45;
    30.             angle.y=Mathf.Round(angle.y/45)*45;
    31.         }
    32.  
    33.         offset=new Vector3(0,40,-40);
    34.         offset=Quaternion.Euler(0,angle.y,0)*offset;
    35.  
    36.         transform.position = Vector3.Slerp(transform.position, player.position+offset, 3.0f*Time.deltaTime);
    37.         transform.LookAt(player.position);
    38.     }
    39. }
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    That's not a useful metric to judge by. Unity is probably 1000x the game engine that you need but you're using it.

    Much like the way you use Unity, when you use Cinemachine, you use the parts you want and no more.

    Good luck to you in rolling camera code!
     
  8. IAmScoops

    IAmScoops

    Joined:
    May 16, 2021
    Posts:
    9
    That’s very true! A better way to put it would be that I’d rather not implement and learn a new system for something as simple as what I’m looking to do, when I’ve almost achieved my goal. (Some more fiddling around, research, and some good old math got me just about where I want to be!)