In my game I would like to have my character dash to the left or right if I double-tap the A or D key.
I've looked around on the internet and tried most of what I've found with no success.
Is there a simple way to achieve this? Or some resource I could be directed to?
Is there a simple solution for a double-tap?
- Edited
The simplest way to achieve this is to use the <code>KeyDown</code> event of the input system. In this method, you check if the A or D key has been pressed twice, and if so, you can then call the dash command.
Here's a simple example of how this would work:
public class DashOnDoubleTap : MonoBehaviour
{
[SerializeField]
float dashSpeed;
float keyDownTime;
float keyPressDelay = 0.2f; // seconds
private void OnEnable()
{
Input.onKeyDown += HandleKeyDown;
}
private void HandleKeyDown(KeyCode keyCode)
{
// check if the previous key press was less than keyPressDelay ago
if (Time.time - keyDownTime < keyPressDelay)
{
// it was! so this is a double tap!
// Dash in the correct direction
if(keyCode == KeyCode.A)
{
// dash left
Dash(Vector3.left * dashSpeed);
}
else if(keyCode == KeyCode.D)
{
// dash right
Dash(Vector3.right * dashSpeed);
}
}
else
{
// it was a single press, so just save the time
// and get ready for the next press
keyDownTime = Time.time;
}
}
// Dash!
void Dash(Vector3 direction)
- Edited
This bot is going to be absolute cancer soon enough, it's spewing out stuff garbled which is going to confuse the poor newbies.
- Edited
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.
- 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
I hope you found that helpful.
Edit: typos
The AI code is actually correct, but it's for Unity or MonoGame or something. The OP did not mention Godot in the topic, so she didn't know what engine it was for.
cybereality The code doesn't detect if it was the same key twice in a row, only if the second key was A or D. So pressing W then A would count as double tapping A.
- Edited
- Best Answerset by Jakerb
A lot of redundant and overcomplicated code has been posted in this thread for what is actually a pretty simple problem. Here's a generalized simple solution that doesn't use any additional nodes and will report double tap on any key:
const DOUBLETAP_DELAY = .25
var doubletap_time = DOUBLETAP_DELAY
var last_keycode = 0
func _process(delta):
doubletap_time -= delta
func _input(event):
if event is InputEventKey and event.is_pressed():
if last_keycode == event.keycode and doubletap_time >= 0:
print("DOUBLETAP: ", String.chr(event.keycode))
last_keycode = 0
else:
last_keycode = event.keycode
doubletap_time = DOUBLETAP_DELAY
It can also be easily adapted to work with actions instead of keycodes.
The thing about AI is it gets it's 'answers' by stealing other code from the internet which also means that it's going to steal all of the mistakes and nonsense answers as well.
Lethn The thing about AI is it gets it's 'answers' by stealing other code from the internet which also means that it's going to steal all of the mistakes and nonsense answers as well.
From the code integrity point of view, it's worse than just stealing. It concocts snippets from statistical analysis of "stolen" code. The more specific a problem you have, the more jumbled and weird the bot's "solution" will be. That's just the nature of LLMs. And to make things worse for learners, it all looks "legit" and "confident" at first glance, regardless of how broken the code actually is. Observing this is quite amusing
xyz Yes it is funny and ridiculous but at the same time it's not when you try and explain this to people and they get mad they can't fulfil their AI skynet apocalypse scenario, machine learning AI for the purposes that it's now popular to use it for is utter trash. Mind you, I shouldn't complain, it's going to make life so easy for me as competition because all the lazy people out there are going to switch to it thinking it can replace human thinkers when it can't.
because posts in this forum are always about Godot by default, @GodetteAI should know this.
she should also get context about which programming language the post is about:
- if it's not specified anywhere, it's about GDScript
- if it's specified in a tag, it's about the programming language in the tag
- if it's specified in the post's body text, it's about the programing language in the body text
Jakerb
Glad you found it helpful.
Although I went step by step with my answer for understanding, xyz replied with a much cleaner and simpler code.
If you are going to internalize some code, use xyz's one.
His solution is better because:
- if you press any button other than A or D, for example, A F A, double A will not trigger. You can say it is not dependent on you setting keys in Input Map, and checking them manually in code.
- No need for a timer node, time is calculated using delta of _process function, instead of using a node, which is simpler, and needs no setting up.