Dashing Cooldown?

Godot Version

4.6.2.stable

Question

I am wondering how I could add a cooldown to a dash, as of right now, you’re able to just spam the “Sprint” key (Shift) and infinitely dash, I’m a new game dev, so it’s a little hard to understand even the code I write.

extends CharacterBody3D

#--Speed/Movement Vars-
var speed_current = 12.0
const walking_speed = 12.0
const sprinting_speed = 12.0
const crouching_speed = 3.0
const crouch_sprint_speed = 4.5
var jump_velocity = 6.0
var direction = Vector3.ZERO
var crouching_depth = -0.73
var last_velocity = 0.0


#--Player Assets-
@onready var ray_cast_3d: RayCast3D = $"Ceiling Ray"
@onready var head: Node3D = $Head
@onready var standing_collision_shape: CollisionShape3D = $Standing_Collision_Shape
@onready var sliding_collision_shape: CollisionShape3D = $Sliding_Collision_Shape
@onready var eyes: Node3D = $Head/Eyes
@onready var camera_3d: Camera3D = $Head/Eyes/Camera3D
@export var mouse_sens = 0.3
@onready var animation_player: AnimationPlayer = $Head/Eyes/AnimationPlayer

@onready var wall_run_ray_left: RayCast3D = $WallRunRayLeft
@onready var wall_run_ray_right: RayCast3D = $WallRunRayRight


#-- Head Bobbing Vars-

const head_bobbing_sprinting_speed = 17.0
const head_bobbing_walking_speed = 17.0
const head_bobbing_crouching_speed = 10.0

var head_bobbing_sprinting_intensity = 0.2
var head_bobbing_walking_intensity = 0.2
var head_bobbing_crouching_intensity = 0.05

var head_bobbing_vector = Vector2.ZERO
var head_bobbing_index = 0.0
var head_bobbing_current_intensity = 0.0

#--Game Speeds-
var lerp_speed = 8.0

#--Camera Vars
var CameraTiltLeft = 2.5
var CameraTiltRight = -2.5



#--Dashing Vars-
var dash_timer = 0.0
var dash_timer_max = 0.5
var dash_vector = Vector2.ZERO
var dash_speed = 100.0
var dash_cooldown = 10.0
var can_dash = false

#--Sliding Vars-
var slide_timer = 0.0
var slide_max = 1.0
var slide_vector = Vector2.ZERO
var slide_speed = 25.0
var slide_cooldown = 5.0
var can_slide = false

#--Var States-
var walking = false
var crouching = false
var sliding = false
var jumping = false
var dashing = false


func _ready() -> void:
	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

	

func _input(event: InputEvent) -> void:
	if event is InputEventMouseMotion:
		rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
		head.rotate_x(deg_to_rad(-event.relative.y * mouse_sens))
		head.rotation.x = clamp(head.rotation.x, deg_to_rad(-89), deg_to_rad(89))

func _physics_process(delta: float) -> void:
	
	slide_cooldown = clamp(5.0, 0, 5.0)
	dash_cooldown = clamp(10.0, 0, 10.0)
	speed_current = walking_speed
	
	var input_dir := Input.get_vector("A", "D", "W", "S")
	if sliding == true:
		slide_cooldown -= 1.0
	if dashing == true:
		dash_cooldown -= 1.0
	
	if Input.is_action_just_pressed("SlideCrouchSlam") || sliding:
		sliding_collision_shape.disabled = false
		standing_collision_shape.disabled = true
		
		
		# Slide begin Logic
		
		if input_dir != Vector2.ZERO && slide_cooldown == 5.0:
			sliding = true

			slide_timer = slide_max
			slide_vector = input_dir
			print("slide start!")
			animation_player.play("SlideTilt")
		else:
			speed_current = walking_speed
		walking = false
		crouching = true
		
		
	
	
	
	if Input.is_action_just_pressed("SlideCrouchSlam") && !is_on_floor():
		velocity.y = -60
		animation_player.play("Slam")
	elif !ray_cast_3d.is_colliding():
		
		sliding_collision_shape.disabled = true
		standing_collision_shape.disabled = false
		walking = true
		crouching = false
		
		head.position.y = lerp(head.position.y, 1.531, delta*lerp_speed)

	if Input.is_action_just_pressed("Sprint"):
		if input_dir != Vector2.ZERO && slide_cooldown == 5.0:
			dashing = true
			dash_timer = dash_timer_max
			dash_vector = input_dir
			print("dash start!")
		else:
			speed_current = walking_speed



	if Input.is_action_pressed("A"):
		eyes.rotation.z = lerp_angle(eyes.rotation.z, deg_to_rad(CameraTiltLeft), delta * lerp_speed)
	elif Input.is_action_pressed("D"):
		eyes.rotation.z = lerp_angle(eyes.rotation.z, deg_to_rad(CameraTiltRight), delta * lerp_speed)
	else:
		eyes.rotation.z = lerp_angle(eyes.rotation.z, deg_to_rad(0), delta * lerp_speed)

		
	if sliding:
		slide_timer -= delta
		
		if slide_timer <= 0:
			sliding = false
			print("slide End")
			
			
	if dashing:
		dash_timer -= delta * 2.0
		
		if dash_timer <= 0:
			dashing = false
			print("Dash end")
	# Handle Head Bob
	if walking:
		head_bobbing_current_intensity = head_bobbing_walking_intensity
		head_bobbing_index += head_bobbing_sprinting_speed*delta

	#--Handle Landing
	
	if is_on_floor():
		if last_velocity.y < -10.0:
			animation_player.play("Hard Land")
		elif last_velocity.y < -4.0:
			animation_player.play("Landing")
			
			
			
	if is_on_floor() && !sliding && !dashing && input_dir != Vector2.ZERO:
		head_bobbing_vector.y = sin(head_bobbing_index)
		head_bobbing_vector.x = sin(head_bobbing_index/2)+0.5
		
		eyes.position.y = lerp(eyes.position.y, head_bobbing_vector.y*(head_bobbing_current_intensity/2.0), delta*lerp_speed)
		eyes.position.x = lerp(eyes.position.x, head_bobbing_vector.x*(head_bobbing_current_intensity), delta*lerp_speed)
	else:
		eyes.position.y = lerp(eyes.position.y, 0.0, delta*lerp_speed)
		eyes.position.x = lerp(eyes.position.x, 0.0, delta*lerp_speed)
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta
		slide_timer = 0.0
		can_slide = false

	# Handle jump.
	if Input.is_action_just_pressed("Jump") and is_on_floor():
		velocity.y = jump_velocity
		jumping = true
		sliding = false
		can_slide = false
		animation_player.play("Jump")
	if jumping:
		can_slide = false
		crouching = true
		jumping = true
		
		
		

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.

	direction = lerp(direction,(transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(), delta*lerp_speed)
	
	if sliding:
		direction = (transform.basis * Vector3(slide_vector.x, 0, slide_vector.y)).normalized()
		speed_current = (slide_timer + 0.2) * slide_speed + 0.5
		head.position.y = lerp(head.position.y, 1.531 + crouching_depth, delta*lerp_speed)
		standing_collision_shape.disabled = true
		sliding_collision_shape.disabled = false
	if dashing:
		direction = (transform.basis * Vector3(dash_vector.x, 0, dash_vector.y)).normalized()
		speed_current = (dash_timer + 0.2) * dash_speed + 0.5
	if direction:
		velocity.x = direction.x * speed_current
		velocity.z = direction.z * speed_current
		
	else:
		velocity.x = move_toward(velocity.x, 0, speed_current)
		velocity.z = move_toward(velocity.z, 0, speed_current)
		standing_collision_shape.disabled = false
		sliding_collision_shape.disabled = true
	last_velocity = velocity
	
	
	
	move_and_slide()

When you have the code to detect an input to dash you Can check a boolean. Then when you dash you set it to false and start a timer. When it finishes you set the boolean to true
This is a pseudocode implementation:

var can_dash : bool = true

func _process() -> void:
    if dash_input_check and can_dash:
        can_dash = false
        dash code
        await get_tree.create_timer(dash cooldown time).timeout
        can_dash = true

@normalized, is this a okay implementation of await or do you think a timer should be used?

1 Like

Technically, it’s fine to have an await in _process() like this as long as you guard it with a boolean to prevent turning more than one instance of _process() into a sleeping coroutine. However, I’d still recommend doing it with a timer. Many people will not interpret correctly what the await is doing here and will be tempted to copy this approach for something else, forgetting to properly guard it, causing weird bugs.

1 Like