How we can use "Match" with "Input.is_action_pressed()"?

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

-Godot 3.1.1 Stable

Using currently:

if Input.is_action_pressed("ui_left"):
if Input.is_action_pressed("ui_right"):
if Input.is_action_pressed("ui_down"):
if Input.is_action_pressed("ui_up"):

It is possible to use match to eliminate these bunch of if?

match Input.is_action_pressed():
    "ui_left":#stuff
    "ui_right":#stuff

Couldn’t figure it out as it needs a argument in is_action_pressed().

1 Like
:bust_in_silhouette: Reply From: tastyshrimp

Looking at the docs for the Input I don’t see a way to do like you mention, as there are not methods that would allow something like that. But I can see 2 different ways you could do it, but I’m not sure you should.

  1. Forget everything about the Input and use InputEvent by implementing the _inputs method, by doing that you can catch open the event and use the to_text() to check what key was pressed. And since the to_text method returns a string it can be directly put into the match.
    A warning, I wouldn’t do this because you lose the entire InputMap thing and are basically processing the raw inputs manually and ignoring all the niceties Godot provides

  2. You change the way you process entirely, you declare a Dictionary where the keys are the inputs and the value is the function that processes that input, ideally you would use a lambda for this but it seems to not be supported yet, github issue for tracking, so as a poor men replacement you can save the function name as the value.
    Then whenever you are checking for inputs, you loop through the keys of the dictionary searching for a match and whenever there is one you use the call method to call the appropriate function. Something like this:

for key in inputsDictionary.keys():
    if Input.is_action_pressed(key):
        call(inputsDictionary[key])

This will probably work, but i’m not sure if it worth the effort.

Your writing was really easy to follow, you make tutorials don’t you? :slight_smile: I got what you mean in point 1, will be looking more into what you elaborated in point 2, looks interesting, thank you for the complete response!

The_Black_Chess_King | 2019-12-26 01:35

I don’t make tutorials, but I work as a software developer and communication is key to make sure everyone understands you, so I got used to it :wink:

tastyshrimp | 2019-12-26 10:10

1 Like

Alrighty friends, for those looking for an elegant solution I might have figured something out:

func _unhandled_input(event):
	var action = what_action_is_event(event)
	if action != null:
		match action:
			"ui_left":
				pass
			"ui_right":
				pass
			etc..

func what_action_is_event(event):
	for action in InputMap.get_actions():
		if event.is_action_pressed(action):
			return action
	return null

using the get_actions() function of InputMap allows you to get an array of all the actions you have defined in String form.
Simply check if the event is one of these and return the action if so.
Then we just match the action as a String.

this allows you to automatically find any action so you don’t need to manually type out a dictionary or array. the only problem I have with this is that I am calling the whole InputMap every time, but I’m sure you could prune the array to only include the actions you care about.

here’s an example with all the pre-enabled actions removed:

var actionArray = []

func _ready():
	prune_actionArray()

func prune_actionArray():
	actionArray = InputMap.get_actions()
	for i in [&"ui_accept", &"ui_select", &"ui_cancel", &"ui_focus_next", &"ui_focus_prev", &"ui_left",
 &"ui_right", &"ui_up", &"ui_down", &"ui_page_up", &"ui_page_down", &"ui_home", &"ui_end", &"ui_cut",
 &"ui_copy", &"ui_paste", &"ui_undo", &"ui_redo", &"ui_text_completion_query", &"ui_text_completion_accept",
 &"ui_text_completion_replace", &"ui_text_newline", &"ui_text_newline_blank", &"ui_text_newline_above",
 &"ui_text_indent", &"ui_text_dedent", &"ui_text_backspace", &"ui_text_backspace_word",
 &"ui_text_backspace_word.macos", &"ui_text_backspace_all_to_left", &"ui_text_backspace_all_to_left.macos",
 &"ui_text_delete", &"ui_text_delete_word", &"ui_text_delete_word.macos", &"ui_text_delete_all_to_right",
 &"ui_text_delete_all_to_right.macos", &"ui_text_caret_left", &"ui_text_caret_word_left",
 &"ui_text_caret_word_left.macos", &"ui_text_caret_right", &"ui_text_caret_word_right",
 &"ui_text_caret_word_right.macos", &"ui_text_caret_up", &"ui_text_caret_down", &"ui_text_caret_line_start",
 &"ui_text_caret_line_start.macos", &"ui_text_caret_line_end", &"ui_text_caret_line_end.macos",
 &"ui_text_caret_page_up", &"ui_text_caret_page_down", &"ui_text_caret_document_start",
 &"ui_text_caret_document_start.macos", &"ui_text_caret_document_end", &"ui_text_caret_document_end.macos",
 &"ui_text_caret_add_below", &"ui_text_caret_add_below.macos", &"ui_text_caret_add_above",
 &"ui_text_caret_add_above.macos", &"ui_text_scroll_up", &"ui_text_scroll_up.macos", &"ui_text_scroll_down",
 &"ui_text_scroll_down.macos", &"ui_text_select_all", &"ui_text_select_word_under_caret",
 &"ui_text_select_word_under_caret.macos", &"ui_text_add_selection_for_next_occurrence",
 &"ui_text_clear_carets_and_selection", &"ui_text_toggle_insert_mode", &"ui_menu", &"ui_text_submit",
 &"ui_graph_duplicate", &"ui_graph_delete", &"ui_filedialog_up_one_level", &"ui_filedialog_refresh",
 &"ui_filedialog_show_hidden", &"ui_swap_input_direction"]:
		actionArray.erase(i)

Then instead of “InputMap.get_actions()” you would put actionArray.

going even further faster if you keep a naming convention for your actions in specific scripts you could have a pruning function like this:

func prune_actionArray():
	for i in InputMap.get_actions():
		if "camera" in i:
			actionArray.append(i)

this is what I’m using for camera controls in my RTS project.

and to make this post actually address the question, you can pass Input into the what_action_is_event() function:

var action = what_action_is_event(Input)
match action:
	"camera_move_right":
		position.x += 10
		etc.