What You’ll Learn in This Hour:
    How nodes receive inputs from player
    Querying for inputs from Input singleton
    Making your game responsive to player’s input
    What Action is and its importance in custom input mapping
    Simulating player’s action using InputEventAction
    Input management is among the most important topics when it comes to game development. Input is what differentiates other kinds of
    entertainment and video games. A game would be very boring if players could not control their characters. Godot engine takes care of difficult
    tasks, such as getting raw data from devices, and provides an easy interface for game developers. It has a very interesting way of integrating
    user inputs with its node system. The engine also provides various helpers to make input handling easier.
    In this hour, you’ll learn how to manage user input and make your game respond to it. We’ll first look at how a node receives inputs from a
    player. Then we will move on to InputEvent class, a class that contains information that needs to properly respond to inputs. After that, we will
    do some coding inGDScript. Then we will take a look at the InputMap singleton and how it can help when players want to choose how they
    want to control the game. Finally, we’ll get to know InputEventAction, a special subclass of InputEvent that can simulate player action.
    Input Basics
    Before we get into more in-depth topics about responding to inputs and managing them, it is important that you know how to acquire those
    inputs in context of the node system of Godot engine.
    Getting User Input
    There are two ways to get user input:
    1. Having a function called every time when the user makes a change. (Using input)
    This is mostly useful when the input of interest involves changes to the input device; for example, choosing button press or release,
    mouse move or click, and screen touch or drag. You might wan
    t
    to get the input this way when dealing with user interface or game
    actions, such as attacking, shooting, using an item, etc.
    2. Querying the device. (Using Input singleton)
    This is useful when you want to know if a specific button is being pressed at the time. You might want to do this every frame (in
    _process callback) to make the player character move when a player holds a button down.
    Most game inputs will fall into either one of the previous cases. When you have to respond to an input, it can be helpful to first ask yourself into
    which category the input falls.
    NOTE
    Limitation of Querying the Device
    Some input events cannot be reliably received by querying the device, as the event ends as soon as it happens. Mouse-wheel scrolling is one
    example. Also, there is no method to query touch-screen events through the Input singleton yet.
    Callbacks
    Node has several callbacks (virtual functions) that can be used to manage inputs. Even when ignoring those not related to inputs, there is still
    quite a lot of them, and this can be confusing to new developers. However, most of the time, you don’t really need more than the following two
    callback functions.
    Input Function
    _input is a virtual function of a generic Node type that is called every time there is a change involving input devices. The node lowest in the
    hierarchy is called first (see Listing 7.1).
    LISTING7.1 Input Function
    Click here to view code image
    func _input(event):
    event is an object derived from the InputEvent class containing information related to the received input. When a node responds to the input,
    it should call get_tree().set_input_as_handled() to prevent other nodes from responding to it again.
    If _input is present in the script, that node will automatically get input callbacks. To manually start or stop getting input callback, use the
    function shown in Listing 7.2.
    111111111
    22222222LISTING7.2 Function to Manually Start or Stop Getting Input Callback
    Click here to view code image
    set_process_input(enable)
    Set enable to false to stop getting callback. Setting it to true will resubscribe the node to receive input events.
    Unhandled Input Function
    _unhandled_input is similar to _input and is also a virtual function of a generic Node type. However, it is called in every node in the tree
    when an input event passed to _input is not marked as handled (Listing 7.3).
    LISTING7.3 Unhandled Input Function
    Click here to view code image
    func _unhandled_input(event):
    event is the same object of the InputEvent class containing information related to the received input. This function is called when the previous
    input is not handled by any node. It can be disabled and re-enabled the same way as _input. See Listing 7.4.
    LISTING7.4 Function to Manually Start or Stop Getting Unhandled Input Callback
    Click here to view code image
    set_process_unhandled_input(enable)
    Similar to _input, setting enable to false stops the node from getting callback. Setting it to true will resubscribe the node to receive
    unhandled input events.
    For a simple game, you can use either _input or _unhandled_input, but for more complex games, it is suggested you put actual game
    controls, such as character movement, in the _unhandled_input function and leave _input to nodes that receive specific events to
    handle them first. This includes advancing message dialog and setting them as handled. That’s one way to prevent your player character from
    moving away while there’s a message displayed on screen.
    NOTE
    Nodes with Special Input Handling
    There are several nodes that have additional methods for input handling. To name a few:
    Viewport node can check for mouse position inside itself.
    CollisionObject and its 2D counterpart, CollisionObject2D, can receive input events through Camera. You can click on objects directly
    this way.
    Control node also has a callback similar to those discussed previously: _gui_input(event).
    This function is a bit different from previous functions, since it is local to Control. It is only called when it has the focus or the input happens
    within its boundary. You only have to use this function when making your own control, as Godot engine provides an easier-to-use signal system.
    The Control node and GUI are further discussed in Hour 9, “User Interface.”
    Input Singleton
    Input is a singleton that manages inputs at global level. It is ideal for querying if a specific button is pressed, setting cursor position,
    capturing the cursor inside a game window, and containing input settings that affect the whole game. Listing 7.5 shows some of the helper
    functions.
    LISTING7.5 Input Singleton Helper Functions
    Click here to view code image
    Input.is_key_pressed(scancode)
    Input.is_mouse_button_pressed(button)
    Input.is_joy_button_pressed(device, button)
    What you should put between the parentheses can be found in the @Global Scope section of Godot Engine APIDocumentations. Keyboard
    buttons are prefixed with KEY
    . For example, KEYESCAPE for escape (esc) key, KEY_RETURN for enter key, KEY_M for letter ‘M’ key, etc.
    Mouse buttons are prefixed with “BUTTON
    ”. Examples include BUTTONLEFT and BUTTON_WHEEL_DOWN.
    InputEvent Class
    InputEvent is a class that contains information about user input. As you may have noticed from the previous topic, it is given to callback
    functions as an only parameter, so it is very important that you thoroughly understand this class.
    Subclasses
    InputEvent itself has very limited uses. Most important are the subclasses that derive from this class. Listing 7.6 shows the hierarchy of
    subclasses derived from InputEvent.
    111111111
    22222222LISTING7.6 Subclasses of InputEvent Class
    Click here to view code image
    InputEvent
    InputEventAction
    InputEventJoypadButton - for joystick or gamepad button.
    InputEventJoypadMotion - for joystick hat movement.
    InputEventScreenDrag - for swiping on a touch screen.
    InputEventScreenTouch - for tapping on a touch screen.
    InputEventWithModifiers
    InputEventKey - for keyboard buttons.
    InputEventMouse
    InputEventMouseButton - for mouse buttons and mouse wheel scroll.
    InputEventMouseMotion - for mouse movement.
    The InputEventAction class simplifies user inputs to game actions, such as “move player character forward.” We will discuss more about
    this class later. The InputEventWithModifiers class, like its parent, has almost no uses on its own. Derived classes can be checked for
    usage of modifier keys, such as control (ctrl) keys, alternate (alt) or meta keys, and shift keys. The InputEventMouse class also has very
    little use on its own. Derived classes are events generated by the mouse. This means that the cursor position associated with events is
    available for you to use. This might seem like a lot, but we will take a look at each one individually in subsequent topics.
    Keyboard and Joystick Input
    Let’s start coding some GDScript to better visualize what we have learned so far and how it can be applied in game development withGodot
    engine. We are going to handle basic keyboard and joystick inputs.
    Keyboard Input
    Create a new node of any type (this example will use generic Node type), so attach a GDScript to it. It doesn’t matter if the script is built in or
    not. Type the script (you can omit the code comments) in Listing 7.7.
    LISTING7.7 Basic Keyboard Input Handling Script
    Click here to view code image
    extends Node
    # _input callback will be called when a keyboard button is pressed or released.
    func _input(event):
    # The event of interest is keyboard event, which is of class InputEventKey.
    if event is InputEventKey:
    # Display the word “Echo” at the end of the line if this event is an echo
    var is_echo = “Echo” if event.echo else “”
    if event.pressed:
    # When the player holds a button down, display “Key pressed”, scancode and whether it’s an echo
    prints(“Key pressed”, event.scancode, is_echo)
    else:
    # Same as above, but display “Key released” when the key is released
    prints(“Key released”, event.scancode, is_echo)
    Save the script and the scene. Try running the game. Try pressing a key button, then release it. Try pressing several ones simultaneously. See
    how the texts are printed to console by your inputs. The number following the “Key pressed” or “Key released” text is the same value as defined
    in @Global Scope. For example, number 16777217 stands for KEY_ESCAPE. It can be very difficult for developers to debug the game when
    keys are represented as numbers. For this, OS singleton has a function that converts a scancode into human-readable text (Listing 7.8).
    LISTING7.8 Function to Convert Scancode into Human-Readable Text
    Click here to view code image
    OS.get_scancode_string(scancode)
    Try using this function with the previous code. Now you are able to see the name of the pressed key in text.
    Try holding a key down for a bit. You may notice that when you hold a key down, text repeatedly prints to the output with the word “echo” at the
    end of the line. This is the result of event.echo. It signifies that the InputEventKey is repeated automatically. You may also notice there
    is a fixed delay before this happens. This may remind you of a similar behavior in a text editor. When you hold a key down and wait a bit, the
    letter begins repeating as if you manually typed it very fast. Although it is useful when you make your own text input control, this behavior is
    rarely used in games. The player character should walk normally as the player holds the walk key down. We don’t need to simulate the button
    being pressed repeatedly. To prevent echoes from being processed as normal inputs, simply create another condition for it, like what is shown
    in Listing 7.9.
    LISTING7.9 Prevent Echoes fromBeing Processed as Normal Inputs
    Click here to view code image
    if event is InputEventKey && !event.echo:
    Let’s try handling “keyboard button holding” using Input singleton (Listing 7.10).
    LISTING7.10 Using Input Singleton Inside Process Callback to Handle Keyboard Button Holding
    Click here to view code image
    111111111
    22222222extends Node
    func _process(delta):
    # KEY_SPACE is an alias for 32, a scancode for spacebar
    if Input.is_key_pressed(KEY_SPACE):
    print(“Holding spacebar”)
    Try pressing and releasing the spacebar. You’ll notice that it outputs “Holding spacebar” not only the moment you press or release it, but every
    frame that you hold it down. This is very useful when you want to check if, for example, a character should move in this frame or not. With
    Using _process, you will have access to the delta variable. This variable tells how much time has passed since the last frame, and it
    varies each frame. It’s very important to take this variable into account to keep the movement speed constant. Also, unlike previous handling
    with echo, there is no delay between the button pressing and function calling.
    At this point, you should be able to tell the differences between using _input and Input singleton.
    Moving a Sprite with Keyboard
    Printing texts is boring, so let’s try controlling a Sprite using GDScript with knowledge from the previous topic. Create a new node of type
    Sprite and set its texture. You can use the default robot icon. Attach the following GDScript shown in Listing 7.11.
    LISTING7.11 Controlling a Sprite Node
    Click here to view code image
    extends Sprite
    export var SPEED = 100
    func _process(delta):
    var direction = Vector2(0, 0)
    if Input.is_key_pressed(KEY_UP):
    direction.y -= 1
    if Input.is_key_pressed(KEY_DOWN):
    direction.y += 1
    if Input.is_key_pressed(KEY_LEFT):
    direction.x -= 1
    if Input.is_key_pressed(KEY_RIGHT):
    direction.x += 1
    direction = direction.normalized() # To make sure diagonal movements will be in
    the same speed
    direction = SPEED delta # Multiply by speed (pixels per second) and
    the time passed (seconds)
    translate(direction) # Move the Sprite by the direction vector
    Try running the game and using directional keys to move the Sprite.
    Joystick Input
    Now let’s continue handling joystick input. Godot engine abstracts gamepad and joystick layout so that the same script can work with different
    controller brands. You’ll need a game controller to test your code. Edit your script into the code shown in Listing 7.12, save it, and try running
    the game.
    LISTING7.12 Basic Joystick Input Handling Script
    Click here to view code image
    extends Node
    func _input(event):
    if event is InputEventJoypadButton:
    # print the button index
    prints(“Button:”, str(event.button_index))
    Try pressing all joystick or gamepad buttons. Take note of the button index of directional keys. You will need them in the upcoming exercise.
    Again, the human-readable button index values can be found in @Global Scope section of the documentations. It is prefixed by
    “JOY_BUTTON
    ”.
    Moving a Sprite with Joystick: Exercise
    Let’s try controlling a Sprite using the joystick the same way we did with the keyboard. Create a new node type of Sprite and set its texture.
    Attach the following GDScript shown in Listing 7.13. Be sure to fill in the blanks with the button index you get from the previous step.
    LISTING7.13 Controlling a Sprite Node Using Joystick: Exercise
    Click here to view code image
    extends Sprite
    const SPEED = 100
    var deviceindex = 0
    func ready():
    111111111
    22222222Input.connect(“joyconnectionchanged”, self, “joyconnect”)
    func joy_connect(index, connect):
    # When a joystick is detected, keep the device index in a variable
    if connect:
    device_index = index
    func _process(delta):
    var direction = Vector2(0, 0)
    # Query Input singleton with the device index
    if Input.is_joy_button_pressed(device_index,
    ): # UP
    direction.y -= 1
    if Input.isjoybuttonpressed(deviceindex, _): # DOWN
    direction.y += 1
    if Input.isjoybuttonpressed(deviceindex, _): # LEFT
    direction.x -= 1
    if Input.isjoybuttonpressed(deviceindex, _): # RIGHT
    direction.x += 1
    direction = direction.normalized() # To make sure diagonal movements will be in the
    same speed
    direction = SPEED delta # Multiply by speed (pixels per second) and the
    time passed (seconds)
    translate(direction) # Move the Sprite by the direction vector
    Try running the game and use directional keys of the joystick to move the Sprite. Did you get all the button indices correctly? If your Sprite did
    not go where you expected, try switching the button index around.
    Mouse and Touch Input
    A large portion of gamers may prefer to use game controllers to play, but for some genres, such as first-person shooters (FPS), the mouse is
    also a viable option due to its precision. Games on mobile devices can make use of touch screen if the device has one. We’ll learn how to
    respond to inputs from such devices.
    Mouse Input
    Similar to keyboard and joystick input, mouse inputs can be handled by following the code in Listing 7.14, which is using _input callback.
    LISTING7.14 Basic Mouse Input Handling Script Using Input Callback
    Click here to view code image
    func _input(event):
    if event is InputEventMouseButton && event.pressed:
    prints(“Button”, event.button_index, “is pressed at”, str(event.position))
    if event is InputEventMouseMotion:
    prints(“Mouse moved to”, str(event.position))
    The following code in Listing 7.15 uses Input Singleton:
    LISTING7.15 Basic Mouse Input Handling Script Using Input Singleton
    Click here to view code image
    func _process(delta):
    if Input.is_mouse_button_pressed(BUTTON_LEFT):
    prints(“Holding left mouse button at”, get_tree().get_root()
    .get_mouse_position())
    Moving a Sprite with Mouse
    Let’s do the same as we did in the previous topic. Create a new Sprite node, set its texture, and attach the script shown in Listing 7.16.
    LISTING7.16 Controlling a Sprite Node Using Mouse
    Click here to view code image
    extends Sprite
    func _input(event):
    if event is InputEventMouseMotion:
    position = event.position
    Try moving the mouse cursor inside the game window. The Sprite is now stuck to the cursor.
    Touch Input
    Touch input events can be handled like that shown in Listing 7.17:
    LISTING7.17 Basic Mouse Input Handling Script Using Input Callback
    Click here to view code image
    func _input(event):
    111111111
    22222222if event is InputEventScreenTouch && event.pressed:
    prints(“Screen touch at”, str(event.position))
    if event is InputEventScreenDrag:
    prints(“Screen drag at”, str(event.position))
    If you do not possess a device with a touch screen or you prefer to test the game in the desktop, go to Project > Project Settings > General >
    Display-Window > Handheld > Emulate Touchscreen and turn this option on.
    Moving a Sprite with Touchscreen
    Let’s finish this topic with the same example. Again, create a new Sprite node, set a texture to it, and attach the script shown in Listing 7.18.
    LISTING7.18 Controlling a Sprite Node Using Touchscreen
    Click here to view code image
    extends Sprite
    func _input(event):
    if event is InputEventScreenTouch:
    position = event.position
    The Sprite should now go wherever you tap.
    Input Mapping
    It is generally more beneficial to use Action and Input Mapping instead of defining individual keys in the script so that it can be easily ported to
    various platforms with minimal change to code. Most of the time, players are going to play your game with default controls given to them, but it
    would be nice to give them the opportunity to edit the controls so they can get into your game more easily and comfortably. However, in other
    engines or frameworks, this can be a burden to developers. Not only do they have to keep a list of user-defined controls, the game must be
    saved and reloaded each time it is launched. To help developers focus on more important things, Godot engine provides easy interfaces for
    this task, Action and Input Map.
    Action
    Action is basically a group of input events that achieve the same task. It can be named to reflect what it does in the game. For example,
    “move_up” Action has both KEY_W and KEY_UP in it. When a player presses either the ‘W’ key or up arrow key,
    Input.is_action_pressed(“move_up”) will return to true. You can check for this condition and make the player character move as
    a result.
    Listing 7.19 uses Using _input.
    LISTING7.19 Handling Input Defined in Action Using Input Callback
    Click here to view code image
    func _input(event):
    if event.is_action(“move_up”):
    if event.pressed:
    print(“start walking”)
    else:
    print(“stop walking”)
    Using Input singleton is shown in Listing 7.20.
    LISTING7.20 Handling Input Defined in Action Using Input Singleton
    Click here to view code image
    func _process(delta):
    if Input.is_action_pressed(“move_up”):
    print(“walk”)
    This way, you don’t have to check each individual key for a matching event. You also don’t have to worry about user-mapped control. As long
    as it is in an Action, you can refer to it by the Action’s name.
    Modifying Actions in your game can be done prior to running the game using Input Map in the Project Settings or while in-game using
    InputMap singleton.
    The Input Map of your project is accessible from the top-left menu bar. Choose Project > Project Settings > Input Map. Here, you’ll find several
    default Actions that you can use, such as ui_accept, ui_cancel, etc. These default Actions cannot be deleted, as they are used by
    Control and its derivatives. You can add your own Action by typing the name in the text box and pressing a button that says “Add.” The newly
    created Action will appear at the bottom of the list. You may add an event to it by pressing the
    button next to the Action’s name on the right.
    Choose the type (Key, Joy Button, Joy Axis, or Mouse Button) to configure the button. Finally, press the “OK” or “Add” button. Editing or
    deleting an event from an Action can be done by pressing the
    icon or the
    icon, respectively.
    InputMap Singleton
    Input Map is a user interface provided by the editor. The engine will pass all Actions in the Input Map to the InputMap singleton and
    automatically add them before the game starts. It is actually the InputMap singleton that does the job behind the scenes.
    111111111
    22222222InputMap singleton keeps a list of Actions and events associated with each of them. Here you can add an Action, add an event to an Action,
    and check if an event matches an Action. It is very useful when you want to save or load user-defined controls. You can get Action and event
    lists by calling Listing 7.21.
    LISTING7.21 Functions to Get List of Actions and Events in InputMap
    Click here to view code image
    for action in InputMap.get_actions():
    var list = InputMap.get_action_list(action)
    Then you can serialize the output to a configuration file by a method that works best for your game.
    InputEventAction
    InputEventAction is a special subclass of InputEvent. Unlike other subclasses of InputEvent that represent changes in status of input devices,
    it represents an Action. It can be used to simulate player actions. For example, a game has “move_up” Action, associated to KEY_UP,
    defined in the Input Map. You want to simulate this Action as part of auto-move function. You may achieve this by using Listing 7.22.
    LISTING7.22 Using InputEventAction
    Click here to view code image
    var action_move_up = InputEventAction.new()
    func _ready():
    action_move_up.action = “move_up”
    action_move_up.pressed = true
    func auto_move():
    Input.parse_input_event(action_move_up) # Input.action_press(“move_up”) also
    works
    func _process(delta):
    if Input.is_action_pressed(“move_up”):
    move(Vector2(0, -1) delta)
    From the previous code, if auto_move is called, action_move_up is processed as if the player generated it. Since this action is a
    “pressed” action as defined by action_move_up.pressed = true, the game continues as if the button is held down indefinitely. You
    can pass another “release” Action to stop imaginary button holding or use Input.action_release(“move_up”).
    NOTE
    Devices Can’t Create InputEventAction
    InputEventAction will never be created by input devices. It can only be created via scripting or in the Inspector dock.
    Summary
    In this hour, you learned the differences between using _input and Input singleton to acquire player inputs. You learned how to respond to
    these inputs by using various properties of InputEvent. You were able to apply it with the Sprite node movement. You also learned about Action
    and InputMap and how they can be used in place of naming buttons. Finally, you learned about InputEventAction and saw one example
    of how it can be used.
    Q&A
    Q. Which is better: child nodes have their own _input function or only the parent node has _input function and manages it for
    its children?
    A. There is no solution that works for every project. Both have their pros and cons. For reference, Godot engine codebase in C++ has some
    forms. One could say that it is easier to maintain, because there is only one _input function and the relationship with its children can be
    relatively easy to guess just by looking through the code. The downside is that the children depend on their parent and cannot work on their
    own. Generally, if you want your node to work on its own, put _input function in it, but if this functionality is not the case, you can do it
    either way.
    Workshop
    Answer the following questions to make sure you understood the content of this hour.
    Quiz
    1. Given event is InputEventMouse is true, event is InputEvent will be true or false?
    2. If you want to call a function every time the player scrolls a mouse wheel, what callback functions would be the most appropriate place to
    check for input: _ready, _process, _input, or _tree_exited?
    3. Regarding the following GDScript of a node inside the Scene Tree (Listing 7.23), how many lines of the text “Godot” would be printed if
    you type in the game window, one letter at a time, “g,” “o,” “d,” “o,” and “t,” then release all keyboard buttons?
    111111111
    22222222LISTING7.23 Quiz 3: GDScript of a Node Inside Scene Tree
    Click here to view code image
    extends Node
    func _input(e):
    if e is InputEventKey && !e.echo:
    print(“Godot”)
    4. Regarding the following GDScript of a node inside the Scene Tree (Listing 7.24), what would be printed to the output console if, after
    “READY” is printed:
    1. The left mouse button is clicked?
    2. The mouse cursor is moved inside the game window?
    3. The “Escape” key is held down?
    4. The letter “M” key is held down?
    5. The “Enter” key is released?
    LISTING7.24 Quiz 4: GDScript of a Node Inside Scene Tree
    Click here to view code image
    extends Node
    var event = Sprite.new()
    func _ready():
    set_process_unhandled_input(false)
    if Input.is_mouse_button_pressed(BUTTON_LEFT):
    print(“Left”)
    print(“READY”)
    func _process(dt):
    if event is InputEventMouseMotion:
    print(event.position.x)
    if Input.is_key_pressed(KEY_ESCAPE):
    print(“Quit”)
    func _input(e):
    if e is InputEventKey && !e.pressed:
    print(“Key”)
    elif e.is_action(“ui_accept”):
    print(“Enter”)
    func _unhandled_input(e):
    if e is InputEventKey:
    print(“Unhandled Key”)
    5. Regarding the same GDScript in problem number 4, with the set_process_unhandled_input(false) line removed, what is the
    function you would call to prevent “Unhandled Key” from being printed when “Key” or “Enter” is printed because of the same InputEvent?
    Answers
    1. true. InputEventMouse is one of the subclasses of InputEvent.
    2. _input. Mouse-wheel scrolling cannot be reliably detected by querying Input singleton.
    3. Ten lines—one for pressing and one for releasing, times five.
    4.
    1. Nothing; the input event is queried once before “READY” is printed and is never checked for again.
    2. Nothing; “Left” is never printed because “event” is Sprite, not InputEventMouseMotion.
    3. “Quit”; every frame as long as you hold it down.
    4. Nothing; “Key” will print once you release it.
    5. “Key”; it is not “Enter” at the releasing moment because the event matches the first condition.
    “Unhandled Key” is never printed because of set_process_unhandled_input(false).
    5. get_tree().set_input_as_handled()
    Exercises
    Try to execute the following exercises to get more acquainted with input handling inGodot engine:
    1. Remake “Moving the Sprite using Keyboard” example to make use of Actions.
    2. Add a WASD control scheme to the “Moving the Sprite using Keyboard” example. (The “W,” “A,” “S,” and “D” keys are up, left, down, and
    right, respectively.)
    111111111
    22222222*3.
    Add joystick directional buttons to the “Moving the Sprite using Keyboard” example. Your example should support both keyboard and
    joystick controlling like most games.