Implementing a smooth dash system in a 2D Unity game involves several key parts: detecting input, moving the player rapidly for a short time (dash), and then preventing repeated dashing by using a cooldown. This tutorial will walk you through building that system with clean, frame-rate-independent code using Time.deltaTime
.
✅ What You’ll Learn
By the end of this tutorial, you’ll understand how to:
- Make your 2D character dash in the direction they’re facing.
- Control how long the dash lasts using a timer.
- Prevent the player from dashing again too soon by adding a cooldown.
- Write consistent, reliable dash logic that works smoothly across different frame rates by using
Time.deltaTime
. - Handle everything within the
Update()
method, avoiding the use of coroutines for simplicity and direct control.
🧰 Unity 2D Dash Setup (Quick Steps)
Before we get to the code, make sure your scene is set up properly:
- Create a 2D GameObject for your player character.
- Add a
Rigidbody2D
component to it. - Make sure the Rigidbody’s
Body Type
is set to Dynamic, andGravity Scale
is set to 0 if you don’t want gravity to affect the player. - Attach the following C# script to the player GameObject.

🧠 Full Unity 2D Dash Script (with Timer and Cooldown)
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class PlayerScript : MonoBehaviour
{
private Rigidbody2D rb;
private Animator playerAnim;
[SerializeField] private float moveSpeed = 5;
[SerializeField] private float jumpForce = 10;
private float xInput;
private int facingDirection = 1;
private bool facingRight = true;
[Header("Collision Info")]
[SerializeField] private LayerMask groundLayer;
[SerializeField] private float groundCheckDistance;
private bool isGrounded;
[Header("Dash Info")]
[SerializeField] private float dashSpeed;
[SerializeField] private float dashDuration;
private float dashTime;
[SerializeField] private float dashCooldown;
private float dashCooldownTime;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
playerAnim = GetComponentInChildren<Animator>();
}
// Update is called once per frame
void Update()
{
CheckInput();
CollisionChecks();
Movement();
// Dash and Cool Down
dashTime -= Time.deltaTime;
dashCooldownTime -= Time.deltaTime;
// Flip the player based on input direction
FlipController();
AnimatePlayer();
}
private void CollisionChecks()
{
isGrounded = Physics2D.Raycast(transform.position, Vector2.down, groundCheckDistance, groundLayer);
}
private void CheckInput()
{
// Get horizontal input
xInput = Input.GetAxis("Horizontal");
// Jump on Space key press
if (Input.GetKeyDown(KeyCode.Space))
{
Jump();
}
if (Input.GetKeyDown(KeyCode.LeftShift))
{
DashAbility();
}
}
private void DashAbility()
{
if (dashCooldownTime < 0)
{
dashCooldownTime = dashCooldown;
dashTime = dashDuration;
}
}
private void Movement()
{
if (dashTime > 0)
{
rb.velocity = new Vector2(xInput * dashSpeed, 0);
}
else
{
rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);
}
}
private void Jump()
{
if (isGrounded)
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
}
private void AnimatePlayer()
{
// Animate player running
bool isRun = rb.velocity.x != 0;
playerAnim.SetFloat("yVelocity", rb.velocity.y);
playerAnim.SetBool("isRun", isRun);
playerAnim.SetBool("isGrounded", isGrounded);
playerAnim.SetBool("isDashing", dashTime > 0);
}
private void Flip()
{
facingDirection = facingDirection * -1;
facingRight = !facingRight;
transform.Rotate(0, 180, 0);
}
private void FlipController()
{
if (rb.velocity.x > 0 && !facingRight)
{
Flip();
}
else if (rb.velocity.x < 0 && facingRight)
{
Flip();
}
}
private void OnDrawGizmos()
{
Gizmos.DrawLine(transform.position, new Vector3(transform.position.x, transform.position.y - groundCheckDistance));
}
}
📝 How It Works
This script works by splitting the dash behavior into three key responsibilities: handling input, timing the dash duration, and managing cooldown. When the player presses the dash key (in this case, LeftShift
) and is allowed to dash, the system sets the velocity to a fast value in the character’s facing direction and starts a dash timer. Once the timer runs out, the character’s velocity is reset, and a separate cooldown timer begins counting down before dashing is enabled again.
The use of Time.deltaTime
ensures that both the dash duration and the cooldown countdown are consistent across all machines, regardless of frame rate.
Tips: Systematic Learning Roadmap: Unity Game Development – Systematic Learning Roadmap (2025 Edition)