Can't figure out Dash for Vexx-like game

I’m making a Vexx-like title back from the PS2/Gamecube but for PC. I’ve got the camera movement, jump, Highjump, and movement down.
but dash is not triggering, I set up a Debug and it returned with the prompt but the player didn’t move… any suggestions? Thank you!

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

public class MovementScript : MonoBehaviour
{

   
    public CharacterController controller;
    public Transform cam;
    public Transform groundCheck;
   
    public float speed = 6f;
    public float launchSpeed = 15f;
    public float range = 100f;
    public float gravity = -9.81f;
    public float groundDistance = 0.4f;
    public float jumpHeight = 3f;
    public float launchHeight = 5f;
    public LayerMask groundMask;
    public float dashSpeed;
    public float dashTime;
   
    Vector3 velocity;
    public Vector3 moveDir;
   
    public float turnSmoothTime = 0.1f;
    float turnSmoothVelocity;
    bool isGrounded;
    public bool crouching;
    public bool moving;


    // Update is called once per frame
    void Update()
    {
       
        float horizontal = Input.GetAxisRaw("Horizontal");
        float vertical = Input.GetAxisRaw("Vertical");
        Vector3 direction = new Vector3(horizontal, 0f, vertical);
       
        if(direction.magnitude >= 0.1f)
        {
            float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
            float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
            transform.rotation = Quaternion.Euler(0f, angle, 0f);
           
            Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
            controller.Move(moveDir.normalized * speed * Time.deltaTime);

        }
                    if(Input.GetButtonDown("Jump") && isGrounded)
                    {
                        velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
                    }
                   
                   isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
       
        if(isGrounded && velocity.y < 0)
        {
            velocity.y = -2f;
        }
       
           
            velocity.y += gravity * Time.deltaTime;
           
            controller.Move(velocity * Time.deltaTime);
           
                    crouching = Input.GetKey(KeyCode.LeftShift);
                    moving = Input.GetKey(KeyCode.W);
       
        if(crouching && isGrounded)
        {
            speed = 0f;
        }
        else
            {
                if(!crouching)
                speed = 6f;
            }
           
            if(Input.GetButtonDown("Jump") && crouching && isGrounded)
            {
                 velocity.y = Mathf.Sqrt(launchHeight * -2f * gravity);
            }
             isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
           
            if(Input.GetButtonDown("Jump") && crouching && isGrounded && moving)
            {

               StartCoroutine(Dash());
            
    }
   
    IEnumerator Dash()
    {
        float startTime = Time.time;
       
        while(Time.time < startTime + dashTime)
        {
            controller.Move(moveDir * dashSpeed * Time.deltaTime);
           
            Debug.Log("Dashing");
           
    yield return null;
        }
    }
    }
   
}

Please use the Scripting forum for scripting posts.

I’ll move your post for you.

Dash generally requires that you inhibit normal movement code during the time of the dash, otherwise your normal motion would instantly stop any dash in progress.

This is best accomplished by using either a timer or some distance counter for the duration / length of the dash. While dashing you count that timer down until the dash is complete, or perhaps some other interrupting event happens, such as collision or damage.

EDIT: you may find tutorials that use coroutines for dash; this is also a possibility but a far more complex and problematic solution than a simple timer, for the simple reason that coroutines mimic multi-threading and are difficult to interrupt, such as if your dash gets cancelled mid-stream. A simple dashing timer can be zeroed or restarted at any time, unlike a coroutine.