How to detect a sequence of keys/button pressed ?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By bastien09

Hello there!

Is there a simple way to handle consecutive keys, like for cheat codes ?

Thank you.

I have never seen anything in the documentation to support that but it should be easy enough to build in theory. In your routine that processes input simply add a function to buffer the input

psudo code:
if input="a":
      bufferandcheck("a")
      do the rest

func bufferandcheck(char):
      buffer = buffer.substring(bufferlength-1) + char
      if buffer.contains("cheat"):
            Cheat()

mrLogan | 2018-05-03 11:23

Thanks mrLogan, that’s a neat solution and it can easily handle multiple cheat codes.

bastien09 | 2018-05-03 12:09

Are there any tutorials or other resources where I can find a more detailed explanation of this bufferandcheck function–or the elements therein? Or would you mine explaining it in more detail?

I’m new to coding, and I’m working on a skateboard game. I’m using the basic NES A,B, and directional buttons. I need to make sequential inputs like Tony Hawk Pro Skater. So for instance, a kickflip would be :

A,B, ←

But I also have tricks that will require simultaneous button presses as well. Would I accomplish that with input.is_action_pressed, or input.is_action_just_pressed? Or otherwise?

Any assistance or guidance is appreciated. Thanks.

ZachMoldof | 2019-01-05 02:19

:bust_in_silhouette: Reply From: Poobslag

While it’s not a particularly elegant solution, here is a “Cheat Code Detector” class I created for my game. It has an exportable function which lists all the cheat codes a player can type, and emits a signal when the player types one.

class_name CheatCodeDetector
extends Node
"""
Detects when the player enters cheat codes.
When the player types a key, this class checks whether the user finished typing a cheat code. If a cheat code was
typed, this class emits a signal which can be used to activate the cheat code. Any gameplay effects and sound effects
are the responsibility of the class receiving the signal.
"""

# Signal emitted when a cheat is entered.
signal cheat_detected

# The maximum length of cheat codes. Entered keys are stored in a buffer, and we don't want the buffer to grow to a
# ridiculous size.
const MAX_LENGTH := 32

# Dictionary of key scancodes used in cheat codes, and their alphanumeric representation.
const CODE_KEYS := {
	KEY_SPACE:" ", KEY_APOSTROPHE:"'", KEY_COMMA:",", KEY_MINUS:"-", KEY_PERIOD:".", KEY_SLASH:"/",
	KEY_0:"0", KEY_1:"1", KEY_2:"2", KEY_3:"3", KEY_4:"4", KEY_5:"5", KEY_6:"6", KEY_7:"7", KEY_8:"8", KEY_9:"9",
	KEY_SEMICOLON:";", KEY_EQUAL:"=",
	
	KEY_A:"a", KEY_B:"b", KEY_C:"c", KEY_D:"d", KEY_E:"e", KEY_F:"f", KEY_G:"g", KEY_H:"h", KEY_I:"i",
	KEY_J:"j", KEY_K:"k", KEY_L:"l", KEY_M:"m", KEY_N:"n", KEY_O:"o", KEY_P:"p", KEY_Q:"q", KEY_R:"r",
	KEY_S:"s", KEY_T:"t", KEY_U:"u", KEY_V:"v", KEY_W:"w", KEY_X:"x", KEY_Y:"y", KEY_Z:"z",
	
	KEY_BRACELEFT:"[", KEY_BACKSLASH:"\\", KEY_BRACERIGHT:"]", KEY_QUOTELEFT:"`"
}
# List of cheat codes. Cheat codes should be lower-case, and should not be contained within one another or the shorter
# cheat code will take precedence.
export (Array, String) var codes := []
# Buffer of key strings which were previously pressed.
var _previous_keypresses: String = ""
"""
Processes an input event, delegating to the appropriate 'key_pressed', 'key_just_pressed', 'key_released',
'key_just_released' functions.
"""
func _input(event: InputEvent) -> void:
	if event is InputEventKey and event.scancode in CODE_KEYS:
		var key_string: String = CODE_KEYS[event.scancode]
		if event.pressed and not event.is_echo():
			_key_just_pressed(key_string)
"""
Called for the first frame when a key is pressed.

Parameters:
	'key_string': An single-character alphanumeric representation of the pressed key
"""
func _key_just_pressed(key_string: String) -> void:
	_previous_keypresses += key_string
	# remove the oldest keypresses so the buffer doesn't grow infinitely
	_previous_keypresses = _previous_keypresses.right(_previous_keypresses.length() - MAX_LENGTH)
	for code in codes:
		if code == _previous_keypresses.right(_previous_keypresses.length() - code.length()):
			# Clear the keypress buffer, otherwise a keypress could count towards two different cheats
			_previous_keypresses = ""
			emit_signal("cheat_detected", code)

that worked pretty nice, thx :wink:

Surtarso | 2021-02-28 13:43

This is perfect!! Really, really useful, thank you so much for sharing!

elvisish | 2021-07-22 14:24

Wow awesome, I’m glad you were able to use it!

Poobslag | 2021-07-22 18:00