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

Question Rotating camera to follow player's rotation when standing still

Discussion in 'Scripting' started by accappelen, Jun 18, 2023.

  1. accappelen

    accappelen

    Joined:
    Aug 3, 2020
    Posts:
    2
    Hello all,

    I have been struggling for weeks to get a 3rd person character movement just how I want it. I have got everything working with strafe, and rotating player to look towards camera rotation (Cinemachine) when holding down right mouse button. All I'm missing is getting the camera to "understand" that it needs to rotate to look in the forward direction when the player has rotated and is not holding down RMB.

    My stripped down movement script is like this:
    Code (CSharp):
    1. private void Update() {
    2.     GetInputs();
    3.     Locomotion();
    4. }
    5.  
    6. private void Locomotion() {
    7.     // While holding camera rotate down (RMB):
    8.     if (inputReader.look.sqrMagnitude >= 0.01f && inputReader.movingCameraPressed) {
    9.         var angles = cameraTargetObj.transform.localEulerAngles;
    10.         angles.z = 0;
    11.  
    12.         // Set rotation to the same as cameraTarget rotation is.
    13.         transform.rotation = Quaternion.Euler(0, cameraTargetObj.transform.rotation.eulerAngles.y, 0);
    14.         cameraTargetObj.transform.localEulerAngles = new Vector3(angles.x, 0, 0);  // Then reset it
    15.     } else {
    16.         // Not holding down camera rotate. Allow to rotate in place with Q/E
    17.         rotation = transform.eulerAngles + new Vector3(0, rotationInput * rotateSpeed, 0);
    18.         transform.eulerAngles = rotation;
    19.     }
    20.    
    21.     // ... Handle grounded check, speed, slopes, jumping... Setting velocity value.
    22.    
    23.     controller.Move(velocity * Time.deltaTime);
    24. }
    25.  
    26. private void GetInputs() {
    27.     inputs.y = inputReader.walkAxis;  // W & S
    28.     inputs.x = inputReader.strafeAxis;  // A & D
    29.     rotationInput = inputReader.rotateAxis;  // Q & E
    30.    
    31.     // ... Other inputs..
    32. }
    My player character has a child transform
    cameraTargetObj
    which is placed in Cinemachine Follow. I can rotate this child transform freely (with clamps) and not worry about rotating the camera itself. When I'm holding down RMB, the character will always face the rotation I'm looking at, and I can walk forward/backwards/strafe at the same time while still looking forward. This is great!

    However, when rotating in place (Q/E), the camera is not rotating with. And if I then press forward again the camera still stays in the same rotation - which makes it weird to move because player's forward is now off. I can only correct it by pressing RMB to force the rotation to update.

    I am struggling to understand how forwards works, because while holding RMB and rotating, the blue arrow on
    cameraTargetObj
    points in the right direction - to wherever I aim. But when rotating in place, the player rotates, but the
    cameraTargetObj
    forward does not follow.

    I am unsure how I want the movement to work - preferably I want the camera to rotate left/right when pressing Q/E. Or I might want to allow rotation in place (camera stays still), and when pressing forward, then the camera lerp rotates to look in the player's current forward direction.

    Any help is appreciated!
     
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    First rule of rotation in Unity: don't rely on localEulerAngles or eulerAngles. These are not what you think they are. The values are unstable and unreliable, and btw this is also slow. Quaternions are front and center of rotation, everything else is ephemeral and derived from it, in particular the aforementioned eulerAngles and localEulerAngles.

    Unity comes equipped with a lot of simple but sufficient tools to manipulate quaternions, not even Euler method is really required, it's more of a convenience if anything.

    There are a few ways to achieve this, in your case you already have both rotations, so Quaternion.RotateTowards.
    Code (csharp):
    1. cam.transform.rotation = Quaternion.RotateTowards(cam.transform.rotation, transform.rotation, speed * Time.deltaTime);
    Thousands of posts and articles have been written on rotations, quaternions, and Euler angles. Try looking it up and try learning how to work with quaternions.
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Second rule of Unity: Don't write Camera code if you can just use Cinemachine.

    Why?

    Because camera stuff is really tricky, especially with anything to do with directly manipulating rotations.

    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/
     
    Last edited: Jun 18, 2023
    orionsyndrome likes this.
  4. accappelen

    accappelen

    Joined:
    Aug 3, 2020
    Posts:
    2
    Thanks for the replies. I'm starting to realize Euler is tricky to work with. But I'm not sure how to work with clamping angles (e.g. don't allow player to look further than straight on top of player) with Quaternions.

    I am using Cinemachine. Are you saying there is some Cinemachine settings that allow you to control the camera (only) when doing an input (RMB) with clamps and everything - without code that rotates the player follow child object?

    Anyway I figured it out. I had some old code that canceled my attempts on rotation :oops:. Once I disabled that, rotation worked. But I think I'm going for a proper character controller asset!
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Personally I like to place the camera and tell it to look at a point.

    This controls the rotation in a way that you can reason about far easier than trying to compute an angle.

    If you add some smoothing to those positions you can rapidly make a decent chase cam for just about any purpose.