Help understanding set() and shortcuts

Godot Version

Godot 4.2

Question

I’m working through a tutorial for creating an ability hotkey bar for an rpg. However, the tutorial isn’t explaining some things that are confusing me when I try to mess around with it. I’ve tried clicking on the terms for the relevant documentation but it hasn’t really been helpful.

In particular, I’d like some help understanding how shortcuts work for buttons. Here is the relevant code snippet:

var change_key = "":
	set(value):
		change_key = value
		key.text = value
		
		shortcut = Shortcut.new()
		var input_key = InputEventKey.new()
		input_key.keycode = value.unicode_at(0)
		shortcut.events = [input_key]

Breaking things down:

  1. I don’t quite understand the variable + set(value): syntax. I haven’t seen that up until now. As far as I can tell, the only place value is set is through a regular assignment statement later that’s just change_key = "1"

  2. I don’t understand the shortcut stuff. I for other things I’ve just used the input map in the project settings and checked for those key presses with the strings I had assigned. However, this doesn’t seem to work with this syntax since it seems to need some Unicode value. For single press keyboard inputs I can replicate this by simply providing the character string for the key I want. However, I don’t know how to set this to take mouse inputs or shift key inputs.

  3. Is this ultimately equivalent to using if statements to check for key presses in a process like I did for other things? If so, what are the benefits of doing it one way or the other?

Regarding question 1: This is a feature of GDScript where you have a custom Getter/Setter for a variable to control how the variable is handled.

Properties (Getters and Setters)

In your example, the code is saying “If the user modifies change_key, we want to not only set that value to change_key, but also to the ‘text’ property of ‘key’, as well as do some code (that registers the key as a new Shortcut, etc)”.

3 Likes

Let’s break down the code snippet and clarify the concepts for you.

Variable + set(value) syntax:
This is a shorthand for defining a property with a setter function. In this case, change_key is a variable, and set(value) is a function that sets its value. The set function is called when you assign a value to change_key, like change_key = "1". This syntax is equivalent to defining a separate setter function, but it’s more concise and commonly used in GDScript.

Shortcut and InputEventKey:
In Godot, a Shortcut represents a combination of keys that trigger an action. Here, a new Shortcut is created, and an InputEventKey is added to its events array. The InputEventKey represents a single key press event, and its keycode property is set to the Unicode value of the first character in the value string (e.g., “1” becomes 49, the Unicode code point for the digit 1).

Key presses and input mapping:
You’re correct that using the input map in project settings and checking for key presses with strings is a common approach. However, this code snippet is using a different method, where the Shortcut is created programmatically and tied to a specific button (key.text = value).

Mouse and modifier key inputs:
To add mouse inputs or modifier keys (like Shift), you can modify the input_key object. For example, to add a mouse button event, you can set input_key.type to INPUT_EVENT_MOUSE_BUTTON and input_key.button_index to the desired mouse button (e.g., 1 for the left button). For modifier keys, you can add additional InputEventKey objects to the shortcut.events array with the appropriate keycode values (e.g., KEY_SHIFT for the Shift key).

Benefits of using Shortcuts:
Using Shortcut objects provides a more flexible and efficient way to handle key presses, especially when dealing with complex input combinations. It allows you to define and manage shortcuts programmatically, which can be useful in scenarios like:

  • Dynamic key binding (e.g., letting players customize their own hotkeys)
  • Context-dependent input handling (e.g., different shortcuts for different game states)
  • Simplifying input logic with a centralized shortcut management system

In summary, this code snippet creates a Shortcut object tied to a button, which listens for a specific key press event. While it may seem complex, it provides a powerful way to manage input handling in your game. If you have further questions or need more clarification, feel free to ask!

3 Likes

Thanks for the response. I think I understand the set functionality and the use for the shortcuts.

However, I’m still a little confused about the specifics of the InputEventKey. I don’t see type or button_index in the documentation for the object. And naively trying to add that to the code crashes the scene when I try to play it. Could you clarify and/or provide an example? Perhaps I’m missing some part of the documentation that would help me figure this kind of thing out in the future?

EDIT: I figured out that there is just a separate object for mouse button inputs: InputEventMouseButton. However, I still can’t get this to work properly for some reason. It doesn’t crash on ready anymore and I’ve printed out the resulting object in shortcut.events and used shortcut.has_valid_event() to check to make sure it’s something that works with shortcuts.

However, nothing happens when I press the right mouse button. I have a print statement in the signal catching function so I know that it’s not even getting to that point. When I switch back to the code for the key presses this is still working fine. Any idea what’s up?


it doesn’t appear you should be expecting RMB to do anything from what I can see. You set it but then it doesn’t actually call any functions unless I’m missing something

From what the other comments have explained, using this set() syntax makes it so that assigning a value to the variable calls that whole set() function. Although at the moment I’m only using the string for the text because I just wanted to get the shortcut thing working first before I add logic on taking different inputs.

you did call the set function which is why the print string fired but beyond that you aren’t asking the code to do anything further.
Screenshot 2024-05-27 180649

I have the button emitting a pressed signal. This works if I restore the original code that was using the InputEventKey object instead of the mouse one.

The on pressed event is firing from the pressing of the texturebutton that is the root of the scene not the RMB

Can you explain a bit more? My understanding was that the shortcut acts as if the button was pressed. Why does it work for one case but not the other?

I believe you still need to listen for the shortcut event in your _Input method with matches_event. I could be mistaken though.

Thanks. I got it to work and I learned a really basic thing that somehow hasn’t come up in a tutorial yet. I didn’t realize there was an _input() method like there’s _ready(), _process() etc.

EDIT: Although, follow up question: Why did the original code for the InputEventKey work without the _input() listener?

If you are referring to the InputEventMouseButton.new() then that is just creating a new instance of that class which you can do from most anywhere.

I meant the code from the tutorial that used InputEventKey instead of the InputEventKeyMouseButton. In that case all the code did was create the shortcut, the event, set the keycode of the event, then added it to the shortcut’s events array. That code didn’t use _input(). It just called the set function in _ready() and then the pressed signal from the button is the only place that was listening for the input, at least explicitly in the code from what I can tell. So I’m not sure why only the signal was necessary for the case of a keyboard input but I needed to use the input function for the mouse input.

EDIT: Oh. One other problem: How are you supposed to then trigger the button press within _input()? I just made it emit a pressed signal, but this doesn’t seem to respect the button’s disabled variable, so I can press it again during the timer and it will reset. I can get around this by adding another condition to the if statement, but I want to understand how I’m supposed to do this in order to take advantage of the button’s inbuilt disabled check.