Godot Version
4.3
Question
I’m trying to remake cuphead’s movement and I’m using a timer for the dash’s duration. It sometimes looks like it’s working perfectly, but other times it just cuts mid-air. This only happens when I do the dash in the air and going in the same direction as the last dash. Here’s a video of what happens:
As you can see, this only happens sometimes. Here’s the code:
extends CharacterBody2D
@onready var anim = $AnimatedSprite2D
@onready var max_jump_timer = $Timers/max_jump_timer
@onready var coyote_timer = $Timers/coyote_timer
@onready var dash_timer = $Timers/dash_timer
var speed = 110
var max_speed = 550
var gravity = 0
var jump_force = 1000
var gravity_force = 70
var gravity_force_default = 70
var gravity_force_during_coyote = 40
var dash_speed = 1300
var direction = Vector2.ZERO
var grounded = true
var jump_started = false
var coyote_started = false
var can_coyote = false
var dash_started = false
var can_dash = true
var anim_crouch_started = false
var anim_dash_started = false
var can_move = true
var affected_by_gravity = true
var can_chage_direction = true
var cur_state = STATE.idle
enum STATE {
idle,
idle_shoot,
run,
run_shoot,
jump,
fall,
dash,
parry,
crouch,
crouch_shoot
}
func _process(delta: float) -> void:
if Input.is_action_just_pressed("restart"):
position = Vector2(185, 300)
direction = Input.get_vector("left", "right", "up", "down")
if can_move:
if abs(velocity.x) < max_speed:
velocity.x += speed * direction.x
else:
velocity.x = max_speed * direction.x
else:
velocity.x = 0
if can_chage_direction:
if direction.x > 0:
anim.flip_h = false
elif direction.x < 0:
anim.flip_h = true
grounded = is_on_floor()
#State Machine
match cur_state:
STATE.idle:
can_move = true
affected_by_gravity = true
velocity.x = 0
anim.play("idle")
if not grounded:
cur_state = STATE.fall
else:
if direction.x != 0:
cur_state = STATE.run
if direction.y > 0.3:
cur_state = STATE.crouch
if Input.is_action_just_pressed("jump"):
cur_state = STATE.jump
#if Input.is_action_just_pressed("shoot"):
#cur_state = STATE.idle_shoot
if Input.is_action_just_pressed("dash") and can_dash:
cur_state = STATE.dash
if Input.is_action_just_pressed("down"):
cur_state = STATE.crouch
STATE.idle_shoot:
pass
STATE.run:
can_move = true
affected_by_gravity = true
anim.play("run")
if direction.x == 0:
cur_state = STATE.idle
#if Input.is_action_just_pressed("shoot"):
#cur_state = STATE.run_shoot
if Input.is_action_just_pressed("jump"):
cur_state = STATE.jump
if Input.is_action_just_pressed("dash") and can_dash:
cur_state = STATE.dash
if Input.is_action_just_pressed("down"):
cur_state = STATE.crouch
if not grounded:
can_coyote = true
cur_state = STATE.fall
STATE.run_shoot:
pass
STATE.jump:
affected_by_gravity = true
can_move = true
anim.play("jump")
gravity = -jump_force
if Input.is_action_just_released("jump"):
cur_state = STATE.fall
if not jump_started:
jump_started = true
max_jump_timer.start()
if Input.is_action_just_pressed("dash") and can_dash:
cur_state = STATE.dash
STATE.fall:
affected_by_gravity = true
can_move = true
anim.play("jump")
if can_coyote:
gravity_force = gravity_force_during_coyote
if Input.is_action_just_pressed("jump"):
cur_state = STATE.jump
if not coyote_started:
coyote_started = true
coyote_timer.start()
else:
gravity_force = gravity_force_default
gravity += gravity_force
if grounded:
can_dash = true
gravity = 0
if direction.y == 0:
if direction.x == 0:
cur_state = STATE.idle
else:
cur_state = STATE.run
elif direction.y > 0.3:
cur_state = STATE.crouch
if Input.is_action_just_pressed("dash") and can_dash:
cur_state = STATE.dash
STATE.dash:
print("dashing")
can_dash = false
can_chage_direction = false
gravity = 0
affected_by_gravity = false
can_move = false
if not anim_dash_started:
print("start dash animation")
anim_dash_started = true
play_animation_once("dash")
if not dash_started:
dash_started = true
dash_timer.start()
if anim.flip_h:
velocity.x = -dash_speed
else:
velocity.x = dash_speed
STATE.parry:
pass
STATE.crouch:
affected_by_gravity = true
can_move = false
if not anim_crouch_started:
anim_crouch_started = true
play_animation_once("crouch")
if Input.is_action_just_released("down"):
anim_crouch_started = false
if direction.x == 0:
cur_state = STATE.idle
else:
cur_state = STATE.run
if Input.is_action_just_pressed("dash") and can_dash:
anim_crouch_started = false
cur_state = STATE.dash
STATE.crouch_shoot:
pass
if affected_by_gravity:
velocity.y = gravity
else:
velocity.y = 0
move_and_slide()
$Label.text = anim.animation + ", " + str(cur_state)
func cancel_jump():
cur_state = STATE.fall
func play_animation_once(animation):
anim.play(animation + "_start")
await anim.animation_finished
anim.play(animation)
print("first animation finished")
func _on_max_jump_timer_timeout() -> void:
cancel_jump()
jump_started = false
func _on_coyote_timer_timeout() -> void:
coyote_started = false
can_coyote = false
func _on_dash_timer_timeout() -> void:
dash_timer.stop()
dash_started = false
can_chage_direction = true
anim_dash_started = false
cur_state = STATE.fall
print("dash finished")
I put some prints to know if the dash is being interrupted by its timer or something else, and it confirmed it was the timer.
Any idea what’s happening? Thanks