using UnityEngine; [RequireComponent(typeof(CharacterController))] public class SimpleFPSController : MonoBehaviour { [Header("Movement")] public float walkSpeed = 4f; public float runSpeed = 7f; public float mouseSensitivity = 2f; public float gravity = -20f; [Header("References")] public CharacterController characterController; public Camera playerCamera; public Vector3 PlanarVelocity { get; private set; } public bool HasMovementInput { get; private set; } public bool IsRunning { get; private set; } public float CurrentMoveSpeed { get; private set; } public float SpeedScale { get; set; } = 1f; public bool AllowRunning { get; set; } = true; private float verticalVelocity; private float cameraPitch; private void Awake() { characterController = characterController != null ? characterController : GetComponent(); playerCamera = playerCamera != null ? playerCamera : GetComponentInChildren(); } private void Start() { LockCursor(true); } private void OnApplicationFocus(bool hasFocus) { LockCursor(hasFocus); } private void Update() { HandleMouseLook(); HandleMovement(); } private void HandleMouseLook() { float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity; float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity; transform.Rotate(0f, mouseX, 0f); cameraPitch -= mouseY; cameraPitch = Mathf.Clamp(cameraPitch, -80f, 80f); if (playerCamera != null) { playerCamera.transform.localRotation = Quaternion.Euler(cameraPitch, 0f, 0f); } } private void HandleMovement() { Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); input = Vector2.ClampMagnitude(input, 1f); HasMovementInput = input.sqrMagnitude > 0.001f; IsRunning = AllowRunning && HasMovementInput && Input.GetKey(KeyCode.LeftShift); CurrentMoveSpeed = (IsRunning ? runSpeed : walkSpeed) * Mathf.Max(0.01f, SpeedScale); Vector3 moveDirection = (transform.right * input.x + transform.forward * input.y).normalized; PlanarVelocity = moveDirection * (HasMovementInput ? CurrentMoveSpeed : 0f); if (characterController.isGrounded && verticalVelocity < 0f) { verticalVelocity = -2f; } verticalVelocity += gravity * Time.deltaTime; Vector3 motion = PlanarVelocity; motion.y = verticalVelocity; characterController.Move(motion * Time.deltaTime); } private static void LockCursor(bool shouldLock) { Cursor.lockState = shouldLock ? CursorLockMode.Locked : CursorLockMode.None; Cursor.visible = !shouldLock; } }