10
\$\begingroup\$

I want to make a first person camera that rotates with the mouse.

I looked at the Input.GetAxis Scripting API page and found a sample code, which I have included at the bottom of my post. Upon trying it out, I realized that although it has the same basic functionality I hoped it would have, it does not keep the camera parallel to the xz plane, particularly when moving the mouse in circles. After a while the camera would be at an odd angle, and the player would be completely discombobulated!

Is there a quick fix to this code that would restrict the camera movement somehow, or is there a better way to rotate the camera?

 using UnityEngine;
 using System.Collections;

     public class ExampleClass : MonoBehaviour {
         public float horizontalSpeed = 2.0F;
         public float verticalSpeed = 2.0F;
         void Update() {
             float h = horizontalSpeed * Input.GetAxis("Mouse X");
             float v = verticalSpeed * Input.GetAxis("Mouse Y");
             transform.Rotate(v, h, 0);
         }
     }
\$\endgroup\$
  • \$\begingroup\$ What you are experiencing sounds like gimbal lock. It happens when you are using euler angles for rotation. I'd have to do some testing to offer a solution. Basically, you need to use quaternions. They don't suffer from gimbal lock. \$\endgroup\$ – Fuzzy Logic Jul 28 '15 at 3:56
  • \$\begingroup\$ How would I use a quaternion to do rotation? I tried transform.rotation = Quaternion.Slerp(-Input.GetAxis("Mouse X"), Input.GetAxis("Mouse X"), Time.deltaTime * freeLookTurningSpeed); , but that gave me errors. \$\endgroup\$ – reincarnationofstackexchange Jul 29 '15 at 5:30
  • \$\begingroup\$ Ok, I made a test. Fortunately, it's not gimbal lock. I'll post the solution as an answer for you. \$\endgroup\$ – Fuzzy Logic Jul 29 '15 at 7:28
17
\$\begingroup\$

The problem is that you are updating the existing rotation instead of tracking it yourself and replacing it each update.

When you update the rotation it combines your new rotation with the old one which leads to unexpected behaviour.

The solution is to to keep track of your accumulated rotation and reset the rotation entirely each update with your new values.

Credit where due, I found the answer here: Unity Answers: how-to-lock-or-set-the-cameras-z-rotation-to-zero

Working Code:

using UnityEngine;
using System.Collections;

public class FirstPersonCam : MonoBehaviour {

    public float speedH = 2.0f;
    public float speedV = 2.0f;

    private float yaw = 0.0f;
    private float pitch = 0.0f;

    void Update () {
        yaw += speedH * Input.GetAxis("Mouse X");
        pitch -= speedV * Input.GetAxis("Mouse Y");

        transform.eulerAngles = new Vector3(pitch, yaw, 0.0f);
    }
}

Key differences:

  • Store the yaw and pitch as class members, rather than local method variables so you can keep track of the accumulated values.
  • Use += and/or -= to accumulate each update.
  • Use eulerAngles (to overwrite the rotation value each update) instead of Rotate (which applies your new rotation onto the old one).
\$\endgroup\$
  • \$\begingroup\$ Your welcome. If this solution I posted solved the original problem you were having, you should accept it as the answer. If you would like to get help with your new problem, you should post a new question to keep things tidy and more likely for others to be able to help you or find your question if they are having a similar problem. The comment areas are not meant for extended dialog. Cheers. \$\endgroup\$ – Fuzzy Logic Jul 31 '15 at 6:55
0
\$\begingroup\$

What if you make the camera child of an empty gameobject. Then with one script you manage the empty gameobject rotation relative to UP vector.(MouseX) With another script atached to the camera gameobject you manage rotation relative to Right vector (MouseY)

\$\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.