using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(CharacterController))] public class FPSController : MonoBehaviour { public Camera playerCamera; public float walkSpeed = 9f; public float runSpeed = 18f; public float jumpPower = 7f; public float gravity = 20f; public float lookSpeed = 2f; public float lookXLimit = 45f; public float airAcceleration = 2f; public float groundFriction = 6f; Vector3 velocity = Vector3.zero; float rotationX = 0; public bool canMove = true; CharacterController characterController; void Start() { characterController = GetComponent(); Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } void Update() { Vector3 forward = playerCamera.transform.TransformDirection(Vector3.forward); Vector3 right = playerCamera.transform.TransformDirection(Vector3.right); forward.y = 0; right.y = 0; forward.Normalize(); right.Normalize(); bool isRunning = Input.GetKey(KeyCode.LeftShift); float speed = isRunning ? runSpeed : walkSpeed; Vector3 wishDir = forward * Input.GetAxis("Vertical") + right * Input.GetAxis("Horizontal"); if (characterController.isGrounded) { velocity.y = -0.5f; // Stick to the ground if (canMove) { float drop = velocity.magnitude * groundFriction * Time.deltaTime; velocity *= Mathf.Max(velocity.magnitude - drop, 0) / velocity.magnitude; // Apply friction Accelerate(wishDir, speed, groundFriction); // Ground accelerate if (Input.GetButton("Jump")) { velocity.y = jumpPower; // Jump } } } else { velocity.y -= gravity * Time.deltaTime; // Apply gravity if (canMove) { // Air acceleration is now dependant on how aligned the move direction is with the current velocity direction // The closer to straight ahead, the more acceleration, allowing for more maneuverability while keeping strafe speed under control float currentSpeed = Vector3.Dot(velocity, wishDir); float accel = airAcceleration * Mathf.Max(0, 1 - currentSpeed / speed); Accelerate(wishDir, speed, accel); } } // Apply movement characterController.Move(velocity * Time.deltaTime); // Looking if (canMove) { rotationX += -Input.GetAxis("Mouse Y") * lookSpeed; rotationX = Mathf.Clamp(rotationX, -lookXLimit, lookXLimit); playerCamera.transform.localRotation = Quaternion.Euler(rotationX, 0, 0); transform.rotation *= Quaternion.Euler(0, Input.GetAxis("Mouse X") * lookSpeed, 0); } } // Acceleration function to add force to the velocity in the given direction void Accelerate(Vector3 wishDir, float wishSpeed, float accel) { float currentSpeed = Vector3.Dot(velocity, wishDir); float addSpeed = wishSpeed - currentSpeed; if (addSpeed <= 0) return; float accelerationSpeed = accel * Time.deltaTime * wishSpeed; if (accelerationSpeed > addSpeed) { accelerationSpeed = addSpeed; } velocity += wishDir.normalized * accelerationSpeed; } }