Action Toggle Utility


Every time I take a break from writing GDScript, I make the same set of mistakes, and rediscover the solution for them.

The most common repeating pattern I’ve found myself repeating is:

  1. Write an “_input” function to handle a button being continuously pressed by checking against `event.is_action_pressed(“action”)
  2. Run and test, and be confused why it’s not working.
  3. Realize that is_action_pressed is only for the moment an event is pressed.
  4. Write some code to toggle a boolean for when an action is pressed, and toggle it back when event.is_action_released("action") occurs.

I’ve followed that patterns loads of times. I’ve also forgotten I need to do that every time I start up a new project.

So here is a utility class to handle that 🎉 :

extends Node2D
class_name ActionToggleRegisterClass

var dictionary_of_event_toggle: Dictionary = {}

func listen_to(events: Array[String]):
    for curr_event in events:
        dictionary_of_event_toggle[curr_event] = false

func _input(event: InputEvent):
    for key in dictionary_of_event_toggle.keys():
        if event.is_action_pressed(key):
            dictionary_of_event_toggle[key] = true
        elif event.is_action_released(key):
            dictionary_of_event_toggle[key] = false

func is_toggled(action: String) -> bool:
    if dictionary_of_event_toggle.has(action):
        return dictionary_of_event_toggle[action]
    return false

I personally like to attach all my scripts to a scene 1 so I’ll assume you attached it to a scene called ActionToggleRegister and instantiated that scene on your root.

Assuming you did as much, you can use it by initializing this on your _ready function as such:

func _ready():
    $ActionToggleRegister.listen_to(["move_up", "move_down", "move_right", "move_left"])

And then you can use it as such on your _input(event) function:

    if $ActionToggleRegister.is_toggled("move_up"):
        do_the_thing_for_up()
    if $ActionToggleRegister.is_toggled("move_down"):
        do_the_thing_for_down()

Areas of improvement:

  1. The autocomplete provided by event.is_action_pressed and similar functions is infinitely useful when developing. I tried to replicate using a StringName instead of a string, but the interned strings it auto completed where a bunch other strings, instead of the actions. I’m not sure if that specific autocomplete feature is tied to just those sets of methods in the editor, or if it’s possible for me to provide it myself. I took a VERY quick peek into the C++ code, but I was not able to grok it in my 5 minute read.
  2. Currently, it loops through every registered event on every _input on the ActionToggleRegister scene itself. The input code I’ve written in the past effectively has the same effect except instead of looping, I write the if/else statement myself, so I’m unsure if this is in practice a problem or not.
    1. If I was familiar enough with the input event loop, I’d hope that maybe only a single action gets flipped on each _input call and exit early, but I don’t know if this is the case or not, so I’m assuming it’s not.

  1. I’ve had challenges in the past with importing scripts/classes that are not bound to a scene. It was when I was still first using Godot, and I’m sure the problem was me, and not Godot, but just tying scripts to Scenes have removed the problem, and to my knowledge, without much downside.↩︎

Leave a comment

Log in with itch.io to leave a comment.