Let's use a timer for that.
How will everything work?
Well when you only press A, the character walks left, and D for right.
Whenever you press either buttons, a double tap timer can start. Let's have it be 0.5 seconds.
If you press the button another time within this 0.5 seconds, you will dash.
If you press the other button, the timer restarts.
After 0.5, no double tap will be triggered
0.5 can be changed to whatever makes sense in your game.
Now that we broke down how it will work, let's get to code.
Starting code, just to see where it started:
extends CharacterBody2D
var move_speed: float = 300.0
var direction: Vector2 = Vector2.ZERO
func _physics_process(delta: float) -> void:
direction.x = Input.get_axis("move_left", "move_right")
velocity = direction * move_speed
move_and_slide()
Character moves left and right in the previous code, nothing fancy. "move_left" and "move_right" are set in the project settings input map to A & D buttons, respectively.
Let's have as a child of the Player, a Timer node, whose wait time is 0.5, oneshot is true, autostart is false, and connect its timeout signal to some function like _on_double_tap_timer_timeout.
Let's store the last pressed button of either move_left or move_right in a variable, and whenever we press the same button, we print something.
This is not double tap, but we're getting somewhere:
var last_action_string: String = ""
func _input(event: InputEvent) -> void:
if Input.is_action_just_pressed("move_left"):
if last_action_string == "move_left":
print("move left was already stored")
else:
last_action_string = "move_left"
if Input.is_action_just_pressed("move_right"):
if last_action_string == "move_right":
print("move right was already stored")
else:
last_action_string = "move_right"
Running that, the lines will only be printed when you press the left button twice or more in a row, and the same for the right button. Switching between right and left won't trigger anything, sweet!
Let's start the timer whenever it is not a double tap, the last_action_string will only store the string while the timer is running, because once the timer times out, the function connected to the timeout signal will set the string variable to "":
@onready var double_tap_timer: Timer = $DoubleTapTimer
func _input(event: InputEvent) -> void:
if Input.is_action_just_pressed("move_left"):
if last_action_string == "move_left":
print("move left was already stored")
else:
last_action_string = "move_left"
double_tap_timer.start()
if Input.is_action_just_pressed("move_right"):
if last_action_string == "move_right":
print("move right was already stored")
else:
last_action_string = "move_right"
double_tap_timer.start()
func _on_double_tap_timer_timeout() -> void:
last_action_string = ""
Double tap works, lines only printed when you double tap.
Let's now change the speed of the player whenever we double tap, full code, after refactoring would be like this:
extends CharacterBody2D
@export var dash_speed: float = 600.0
@export var default_move_speed: float = 300.0
var move_speed: float = default_move_speed
var direction: Vector2 = Vector2.ZERO
var last_action_string: String = ""
@onready var double_tap_timer: Timer = $DoubleTapTimer
func _physics_process(delta: float) -> void:
direction.x = Input.get_axis("move_left", "move_right")
velocity = direction * move_speed
move_and_slide()
func _input(event: InputEvent) -> void:
_check_for_double_tap("move_left")
_check_for_double_tap("move_right")
# Literally same code for both "move_left" and "move_right", why not make them into one function
func _check_for_double_tap(action_string: String) -> void:
if Input.is_action_just_pressed(action_string):
if last_action_string == action_string: # If double-tapped
move_speed = dash_speed
else: # If this is not a double-tap
move_speed = default_move_speed
last_action_string = action_string
double_tap_timer.start()
# Connected via the editor
func _on_double_tap_timer_timeout() -> void:
last_action_string = ""
Some issues include, but not limited to:
- Let's say you press A F A fast in sequence, double tap still triggers, and that's because the F button isn't checked for, neither stored in the last_action_string, nor the timer starts too. This is a feature 😠... Seriously you can dash even if you pressed the attack button mid dash double tap.
- This only changes the speed. Dashing for me is a temporary event, where after a second, the player returns to the default speed, this can be done with timers, but that's out of scope of the original question of double taps.
I hope you found that helpful.
Edit: typos