Player should slow down linearly on release

This script does every movement based calculations. At the end I am trying to achieve that the player starts at ‘startSpeed’ and linearly accelerates towards ‘sprintSpeed’ until the W key is held down, which is represented in playerControls.Player.Move . When it finally reaches ‘sprintSPeed’ after around 2 seconds, it keeps that speed until W is released when it stops instantly.

(Deleted irrelevant parts of the code for clarity (like crouching, etc.))

  • My first question is, how I could make that when W is released the player linearly slows down?

  • And the second is, how I could make that when W is released the player linearly slows down at a different rate or speed than it accelerates?

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      public class FirstPersonController : MonoBehaviour
          public bool CanMove { get; private set; } = true;
          private bool ShouldSprint => canSprint && playerControls.Player.Move.ReadValue<Vector2>().y > 0.5f;
          private bool ShouldJump => playerControls.Player.Jump.ReadValue<float>() > 0f && characterController.isGrounded;
          private bool ShouldCrouch => playerControls.Player.Crouch.ReadValue<float>() > 0f && !duringCrouchAnimation;
          [Header("Function Options")]
          [SerializeField] private bool canSprint = true;
          [SerializeField] private bool canJump = true;
          [SerializeField] private bool canCrouch = true;
          [Header("Movement Parameters")]
          [SerializeField] private float walkSpeed = 5f;
          [SerializeField] private float startSpeed = 5f;
          [SerializeField] private float sprintSpeed = 10f;
          [SerializeField] private float crouchSpeed = 3f;
          [Header("Look Parameters")]
          [SerializeField, Range(1, 10)] private float lookSpeedX = 2f;
          [SerializeField, Range(1, 10)] private float lookSpeedY = 2f;
          [SerializeField, Range(1, 180)] private float upperLookLimit = 80f;
          [SerializeField, Range(1, 180)] private float lowerlookLimit = 80f;
          [Header("Jumping Parameters")] //Space
          [SerializeField] private float jumpForce = 8f;
          [SerializeField] private float gravity = 30f;
          [Header("Sprint Parameters")] //Auto
          [SerializeField] private float timeToSprint = 2f;
          private float targetSpeed;
          private bool isSprinting;
          [Header("Crouch Parameters")] //C
          [SerializeField] private float crouchHeight = 1f;
          [SerializeField] private float standingHeight = 2f;
          [SerializeField] private float timeToCrouch = 0.25f;
          [SerializeField] private Vector3 crouchingCenter = new Vector3(0, 0.5f, 0);
          [SerializeField] private Vector3 standingCenter = new Vector3(0, 0, 0);
          private bool isCrouching;
          private bool duringCrouchAnimation;
          private Camera playerCamera;
          private CharacterController characterController;
          private PlayerControls playerControls;
          private Vector3 moveDirection;
          private Vector2 currentInput;
          private float rotationX = 0;
          private void Awake()
              playerCamera = GetComponentInChildren<Camera>();
              characterController = GetComponent<CharacterController>();
              playerControls = new PlayerControls();
              Cursor.lockState = CursorLockMode.Locked;
              Cursor.visible = false;
          private void Update()
              if (CanMove)
                  if (canJump)
                  if (canCrouch)
                  if (canSprint)
          private void HandleMovementInput()
              currentInput = new Vector2((isCrouching ? crouchSpeed : walkSpeed) * playerControls.Player.Move.ReadValue<Vector2>().y, (isCrouching ? crouchSpeed : walkSpeed) * playerControls.Player.Move.ReadValue<Vector2>().x);
              float moveDirectionY = moveDirection.y;
              moveDirection = (transform.TransformDirection(Vector3.forward) * currentInput.x) + (transform.TransformDirection(Vector3.right) * currentInput.y);
              moveDirection.y = moveDirectionY;
          private void HandleSprint()
              if (ShouldSprint) 
          private void ApplyFinalMovements()
              if (!characterController.isGrounded)
                  moveDirection.y -= gravity * Time.deltaTime;
              characterController.Move(moveDirection * Time.deltaTime);
          private IEnumerator SprintAuto()
              float timeElapsed = 0f;
              float currentSpeed = isSprinting ? sprintSpeed : startSpeed;
              float targetSpeed = isSprinting ? startSpeed : sprintSpeed;
              while (timeElapsed < timeToSprint && ShouldSprint)
                  walkSpeed = Mathf.Lerp(currentSpeed, targetSpeed, timeElapsed / timeToSprint);
                  timeElapsed += Time.deltaTime;
                  yield return null;
              if (isSprinting == true)
          private void OnEnable()
          private void OnDisable()

About your questions. You shuld learn about the basic of scripting. Im sure you did not wrote this code, because you cant be asking this then…

do not try to finish a house at first try. First learn to make walls, learn to make floors, learn to make roofs, and when you think you know almost everything, start buildiong a complete house…

1st question: reduce movedirection vector…
2nd question: Create a reduction factor and modyfiy the fctor instead of the result…