Im trying to make a first person camera for the first time...

I am trying to make a first person controller for my game. It works, but it is extremely uncomfortable to use and it is extremely jittery. Can someone help me find an alternative that is simple, fulfills the same purpose, and solves the previously mentioned problems?

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

public class CharacterController : MonoBehaviour {

    public GameObject controlsHelpText;
    public GameObject Player;
    public GameObject Camera;
    public Rigidbody PlayerRB;
    public float speed = 1;
    public float sensitivity = 1;

    private void Start ()
    {
        Cursor.lockState = CursorLockMode.Locked;
    }
    void OnCollisionEnter(Collision col)
    {
        if (col.gameObject.tag == "PowerUp")
        {
            speed += 0.2f;
        }
    }
    void FixedUpdate()
    {
        if (Input.GetKey("w"))
        {
            Player.transform.Translate(0, 0, speed);
        }
        if (Input.GetKey("s"))
        {
            Player.transform.Translate(0, 0, -speed / 2);
        }
        if (Input.GetKey("d"))
        {
            Player.transform.Translate(speed / 2, 0, 0);
        }
        if (Input.GetKey("a"))
        {
            Player.transform.Translate(-speed / 2, 0, 0);
        }
        if (Input.anyKeyDown)
        {
            controlsHelpText.SetActive(false);
        }
    }
    void Update()
    {
        if (Input.GetAxis("Mouse X") > 1)
        {
            Player.transform.Rotate(0, sensitivity, 0);
        }
        if (Input.GetAxis("Mouse X") < -1)
        {
            Player.transform.Rotate(0, -sensitivity, 0);
        }
        if (Input.GetAxis("Mouse Y") > 1)
        {
            Camera.transform.Rotate(-sensitivity, 0, 0);
        }
        if (Input.GetAxis("Mouse Y") < -1)
        {
            Camera.transform.Rotate(sensitivity, 0, 0);
        }
    }

}

@thebluepig333

Before I dive in and try to sort out a better way, I just want to make sure you’re aware - Unity standard assets has a good first person controller. I’m not sure if you just want something that get’s the job done, or you specifically want to build one yourself but I just want to make sure you’re aware of that just in case.

That said, I’ve never been in the habit of using “Transform.translate” - as far as I know this function is not optimal for good movement. You’d probably either want to use a “character controller” and use the CharacterController.Move() function:

CharacterController characterController;
    
        public float MoveSpeed = 3.0f;
        public float JumpHeight= 5.0f;
        public float gravity = 9.8f;
    
        private Vector3 moveDirection = Vector3.zero;
    
        void Start()
        {
            characterController = GetComponent<CharacterController>();
        }
    
        void Update()
        {
            if (characterController.isGrounded)
            {
                moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
                moveDirection *= speed;
    
                if (Input.GetButton("Jump"))
                {
                    moveDirection.y = JumpHeight;
                }
            }
    
            moveDirection.y -= gravity * Time.deltaTime;
    
            characterController.Move(moveDirection * Time.deltaTime);
        }

otherwise you can use a rigidbody, and use Rigidbody.AddForce

Keep in mind your camera.transform.forward is the direction you want to move it in.

Now as for the way you have it now - I wouldn’t move your character in FixedUpdate if I were you. Instead, just do it in Update, and multiply your speed*Time.deltaTime - this is a similar concept to doing it in FixedUpdate, but not the same. FixedUpdate runs at a fixed rate - meaning that frame rate must be lower than update. Time.deltaTime is the number of seconds since the last update was called (usually like .015 or something like that). If you multiply your movement speed by that number, it will change it based on how long an update took, so your speed won’t vary with changing frame rates. It is a better way of ensuring a constant speed than running in FixedUpdate because Time.deltaTime is calculated every update which runs more often than FixedUpdate, meaning you won’t see gaps in the movement (assuming you have an acceptable frame rate).

I’m not sure what you’re trying to do with the rotation, but it looks like it would work very strangely and slowly. With mouse controlled camera movement, you’re supposed to have a pitch and a yaw - now I’m far from an expert on making good camera systems, but with pitch and yaw it goes something like this:

//early declarations

public Transform CameraParent;
public float TrackSpeed;
public Camera MainCam;
// in update

float yaw= Input.getAxis("Mouse X)*Speed*Time.deltaTime;
float pitch= Input.getAxis("Mouse Y")*Speed*Time.deltaTime;
 

MainCam.transform.LocalEulerAngles = new Vector3 (yaw, 0, 0);
CameraParent.LocalEulerAngles = new Vector3(0, pitch, 0);

This is kind of the simplist (not extremely elegant) way one might do it - you have to parent the camera to a transform that will be the pitch(the horizontal look), and the camera itself will only rotate around it’s own x axis.

Keep in mind, I haven’t tested the code I just typed, so it’s highly possible I made some clerical errors, but I hope the point was made and I hope this is helpful. Cheers!

Agree with @thebluepig333, with using the Input.GetAxis(“Horizontal”) / (“Vertical”). In your input manager these are already defined for the ‘wasd’ and arrow keys. As for using translate to move your object, this i have done plenty of times. And agreed again with using the Time.deltaTime. Its far more smooth with the movement .


You could also do something like player.translate(player.forward x speed x time.deltatime) for vertical axis and player.translate(player.right x speed x time.deltatime) for horizontal. Just as an idea. Its what I have done in the past.


For the camera to rotate… well that depends on what you have as a model. If you have a capsule object as your FPS for testing, then just make it a child object and store its transform as a variable. You can rotate localEuler like thebluepig333 suggest. Remember still need to multiply the movement byt time.deltaTime (because its smoother) I did one with a dragon I had modeled, and created a object and had the neck and head rotate so that it pointed at the target and when i would move the mouse it would move the object. So Create and object 5 meters or so and do camera.LookAt(target.transform).
If you have a character modeled and the head is its own object, then attach it to the head and move the head around, but you will still need to manipulate the localEuler or do the target thing.


Hope this helps!