InputEventWithModifiers in Godot – Complete Guide

Navigating the virtual worlds that we create in games is not just about moving characters or interacting with objects; it’s about the subtleties of how we interact. Input events are the core of any interaction in digital experiences, especially in video games. When crafting games with Godot, an open-source game engine, understanding input events is crucial. The InputEventWithModifiers class, an essential part of Godot 4’s input event system, allows developers to create more nuanced and responsive controls. This tutorial will unravel the mysteries of InputEventWithModifiers, offering a deeper understanding of input handling in Godot 4, and through practical examples and explanations, unveil how to enrich the gaming experience with responsive controls that react to various key modifiers.

What is the InputEventWithModifiers Class?

The InputEventWithModifiers class is a vital component in Godot 4’s input system. It’s an abstract base class that extends beyond simple key presses to consider the state of modifier keys. Modifier keys include Shift, Control (Ctrl), Alt, and the Meta key (which corresponds to the Command key on macOS and the Windows key on Windows/Linux). These keys are the unsung heroes of keyboard functionality, providing additional layers of interaction within software.

What is it for?

Godot 4 uses the InputEventWithModifiers class to store information about input events that are affected by these modifier keys. This pertains to a wide range of inputs, such as mouse clicks, keyboard key presses, and even touch gestures. By using this class, developers can determine not only which key or button was pressed but also whether any modifier keys were active at the same time, enabling complex input combinations that are standard in high-quality games.

Why Should I Learn It?

Mastering the InputEventWithModifiers class is critical for game developers who wish to create intuitive and professional-level controls. It allows you to:

– Cater to advanced users who expect the ability to use keyboard shortcuts and modifiers.
– Implement complex gameplay mechanics that require precise control inputs.
– Ensure accessibility by providing different control schemes for users with varied needs and preferences.
– Make your game feel responsive and engaging by giving players a variety of control options.

Learning to implement and utilize the InputEventWithModifiers class in Godot 4 empowers developers to craft richer, more interactive gameplay experiences. With this knowledge, you’re on your way to transforming simple interactions into captivating and dynamic game mechanics.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Handling Basic Input Events with Modifiers

Before we delve into complexes, let’s start by handling some basic input events that involve key modifiers. Let us see how we can capture a single key press with a modifier:

# Example of handling a Ctrl + S key combination for saving
func _input(event):
    if event is InputEventKey:
        if event.pressed and event.scancode == KEY_S and event.control:
            print("Save the game!")

This example shows how to detect when the ‘S’ key is pressed while holding down the ‘Control’ key. Notice how we used the event.control property to check if the Ctrl key is pressed.

Next, let’s see how we can handle a shortcut where a user might want to use Shift with a mouse click to perform a different type of selection:

# Example of handling a Shift + Left Mouse Click 
func _input(event):
    if event is InputEventMouseButton:
        if event.pressed and event.button_index == BUTTON_LEFT and event.shift:
            print("Shift-Click detected!")

In this snippet, we check if a left mouse button click occurs while the Shift key is held down by accessing event.shift. Similarly, you can check event.alt or event.meta for the Alt and Meta keys.

Combining Multiple Modifiers

Real-world applications often require multiple key modifiers to be held down simultaneously. Let’s create a combination that might trigger a debug mode when the user presses Control + Alt + D:

# Example of handling a Ctrl + Alt + D key combination for debugging
func _input(event):
    if event is InputEventKey:
        if event.pressed and event.scancode == KEY_D and event.control and event.alt:
            print("Debug mode activated!")

Here, we’re checking for the D key while ensuring that both the Control and Alt keys are held down, leveraging the power of InputEventWithModifiers to detect this combination.

Moreover, you might want to execute different code depending on the specific modifier keys pressed. Let’s take an example where the player can press the ‘F’ key with different modifiers for various in-game functions:

# Example of handling various F key combinations with modifiers
func _input(event):
    if event is InputEventKey and event.pressed and event.scancode == KEY_F:
        if event.shift:
            print("Applying buff...")
        elif event.alt:
            print("Applying debuff...")
        elif event.control:
            print("Applying heal...")

Here, pressing ‘F’ with Shift, Alt, or Control keys will trigger different print statements simulating different in-game actions.

Creating Custom Shortcut Actions

A fundamental part of game development is establishing smooth and intuitive controls. Let’s create custom shortcut actions using the InputEventWithModifiers. For instance, we’d like to implement a feature where pressing Ctrl + Z undoes an action and Ctrl + Y redoes it:

# Example of a simple undo/redo system using key modifiers
func _input(event):
    if event is InputEventKey and event.pressed:
        if event.scancode == KEY_Z and event.control:
            print("Undo last action!")
        elif event.scancode == KEY_Y and event.control:
            print("Redo last action!")

With this configuration, when the player holds down Ctrl and presses Z or Y, they will trigger actions for undoing or redoing the last action accordingly.

By mastering the usage of InputEventWithModifiers in Godot 4, we’ve taken the first step towards crafting a fluid and intuitive control scheme for any game. These examples form the foundational knowledge required to build upon more advanced input handling and game mechanics. Stay tuned as we dive deeper into Godot 4’s input event system in the next part of our tutorial.

Advanced Input Handling Techniques

As we delve further into advanced input handling with Godot 4, it’s important to explore scenarios that reflect the complexity of a real game environment. This includes reactive controls that need to handle simultaneous key presses and context-sensitive inputs, which add depth and responsiveness to gameplay.

First, let’s illustrate an example where we use a combination of keys and mouse input to control the zoom level of a camera:

# Example of controlling camera zoom with Ctrl + mouse wheel
func _input(event):
    if event is InputEventMouseButton and event.control:
        if event.button_index == BUTTON_WHEEL_UP:
            print("Zooming in...")
        elif event.button_index == BUTTON_WHEEL_DOWN:
            print("Zooming out...")

This code looks for mouse wheel events while the Ctrl key is held down, changing the zoom level accordingly.

Now suppose in your game, the spacebar makes the character jump, but if the player holds down Shift and then presses the spacebar, the character performs a high jump. Here is how this might be handled:

# Example of a high jump with Shift + Spacebar
func _input(event):
    if event is InputEventKey and event.scancode == KEY_SPACE:
        if event.pressed:
            if event.shift:
                print("Performing high jump...")
            else:
                print("Performing regular jump...")

With this snippet, the response to the spacebar press is modified by the Shift key’s state, enabling two types of jumps.

Let’s add a bit more complexity by considering a scenario where the game reacts differently if certain keys are pressed in sequence, such as a combo move in a fighting game:

# Example of a combo move with a sequence of keys
var last_key = null
var combo_time = 0

func _process(delta):
    if combo_time > 0:
        combo_time -= delta
        if combo_time <= 0:
            last_key = null

func _input(event):
    if event is InputEventKey and event.pressed:
        if last_key == KEY_A and event.scancode == KEY_B:
            print("Combo move AB executed!")
            last_key = null
            # Reset the combo timer
            combo_time = 0
        else:
            last_key = event.scancode
            # Start a new combo timer
            combo_time = 0.5

This code monitors key presses and only triggers the combo move if the ‘A’ key is followed by the ‘B’ key within a half-second window.

Next, consider a scenario where different entities in the game can be controlled separately. We might have the following to swap control between entities:

# Example of swapping control between entities with Tab
func _input(event):
    if event is InputEventKey and event.pressed and event.scancode == KEY_TAB:
        if event.shift:
            print("Switching to previous entity...")
        else:
            print("Switching to next entity...")

Tapping the Tab key switches to the next entity, while holding Shift when pressing Tab switches to the previous one. This use of Tab with a modifier provides a seamless control experience.

Lastly, it’s common to have cheat codes or developer shortcuts in games. Here’s an example of how such a feature could be enacted with a specific key sequence using modifiers:

# Example of a cheat code activation with a specific key sequence
var cheat_sequence = [KEY_GODOT, KEY_ENGINE, KEY_BEST]
var sequence_index = 0

func _input(event):
    if event is InputEventKey and event.pressed:
        if event.scancode == cheat_sequence[sequence_index] and event.control:
            sequence_index += 1
            if sequence_index == cheat_sequence.size():
                print("Cheat code activated!")
                sequence_index = 0
        else:
            sequence_index = 0

This code snippet detects a cheat code made up of a specific sequence of key presses combined with the Control key. If the sequence is entered correctly, a message is printed.

These examples demonstrate the versatility of Godot 4’s input handling capabilities. Using InputEventWithModifiers, we can create dynamic and context-sensitive controls that provide a memorable user experience. Whether building a fast-paced action game, an intricate puzzle game, or any interactive software, understanding and leveraging these techniques is invaluable for any developer aiming to deliver responsive controls and engaging gameplay.As we progress, let’s explore the potential of long-press actions within your games. Sometimes, you want an action to occur only if a key or button has been held down for a certain duration.

# Example of handling a long press on the 'T' key for charging a shot
var charging_shot = false
var charge_time = 0

func _process(delta):
    if charging_shot:
        charge_time += delta
        if charge_time >= 1.0: # Assume 1 second threshold for fully charged
            print("Shot fully charged!")
            charging_shot = false

func _input(event):
    if event is InputEventKey:
        if event.scancode == KEY_T:
            if event.pressed:
                charging_shot = true
                charge_time = 0
            elif not event.pressed and charge_time < 1.0:
                print("Shot released too early!")
                charging_shot = false

In the above example, holding down the ‘T’ key starts the charge, and releasing it before it’s fully charged cancels it.

Interactions aren’t limited to single player games. Let’s add functionality for a local multiplayer setting where each player might have a different set of keys.

# Example of handling controls for a two-player local multiplayer setup
func _input(event):
    if event is InputEventKey:
        # Player 1 controls with arrow keys
        if event.pressed:
            match event.scancode:
                KEY_UP:
                    print("Player 1 moves up")
                KEY_DOWN:
                    print("Player 1 moves down")
                KEY_LEFT:
                    print("Player 1 moves left")
                KEY_RIGHT:
                    print("Player 1 moves right")
        
        # Player 2 controls with WASD keys
        if event.pressed and event.shift: # Let's assume Player 2 must hold Shift
            match event.scancode:
                KEY_W:
                    print("Player 2 moves up")
                KEY_S:
                    print("Player 2 moves down")
                KEY_A:
                    print("Player 2 moves left")
                KEY_D:
                    print("Player 2 moves right")

Furthermore, your game might require handling situations where the player needs to quickly tap a button multiple times—a rapid fire mechanic for instance.

# Example of rapid fire with mouse clicks
var click_count = 0
var click_timer = 0.2 # 200ms between clicks

func _process(delta):
    if click_count > 0:
        click_timer -= delta
        if click_timer <= 0:
            print("Rapid fire: ", click_count, " shots!")
            click_count = 0

func _input(event):
    if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.pressed:
        click_count += 1
        click_timer = 0.2

Here, the game tracks how many times the left mouse button is clicked within a 200 millisecond window to determine a rapid fire.

Another common feature in adventure games is to have an interactive inventory, where modifiers can be used to quickly use items.

# Example of using the number keys with modifiers to use items from an inventory
var inventory = ["Potion", "Magic Scroll", "Sword", "Shield", "Bow"]

func _input(event):
    if event is InputEventKey:
        var item_index = event.scancode - KEY_1
        if item_index >= 0 and item_index < inventory.size():
            if event.pressed:
                if event.control:
                    print("Using ", inventory[item_index])
                if event.alt:
                    print("Dropping ", inventory[item_index])

Here, pressing the number keys along with Control will use the item, while pressing them with Alt will drop it.

Now imagine your game includes a musical instrument that is played using the keyboard, where each key corresponds to a different note, and modifiers modify the pitch or volume.

# Example of a musical instrument controlled by the keyboard
var note_map = {
    KEY_A: "C",
    KEY_S: "D",
    KEY_D: "E",
    # Assume mappings for all other notes...
}

func _input(event):
    if event is InputEventKey and event.pressed:
        var note_letter = note_map.get(event.scancode)
        if note_letter:
            var note = note_letter
            if event.shift:
                note = note + "#"
            print("Playing note: ", note)

These examples illustrate the breadth of interaction we can create by harnessing the power of the InputEventWithModifiers class in Godot 4. By thoughtfully implementing various forms of inputs, whether they’re sequential, time-based, or involve multiple modifiers, we can create deep and satisfying gameplay mechanics that delight players and bring our games to life. Complex inputs can be made intuitive, and gameplay becomes more engaging when we give players a rich palette of controls to express themselves within our virtual worlds.

Continuing Your Game Development Journey With Godot

Empowered with the knowledge of handling input events with modifiers in Godot 4, you’re now better equipped to create responsive and complex gameplay mechanics. But this is just the beginning! To further enhance your skills and take your game development journey to the next level, we invite you to explore our comprehensive Godot Game Development Mini-Degree. This series of expertly crafted courses will guide you through the process of building your own games using the power and flexibility of the Godot 4 engine.

Whether you’re a beginner or an experienced developer looking to sharpen your skills, our mini-degree offers a structured learning path covering a variety of critical topics. You’ll dive into using 2D and 3D assets, master the GDScript programming language, learn best practices for gameplay control flow, and much more. By taking these courses, you will build a robust portfolio of games showcasing your newfound abilities, accelerating your path towards becoming a professional game developer.

For those who wish to explore a broader range of topics within this versatile engine, we also provide a variety of Godot courses that cater to all proficiency levels. No matter where you are in your development journey, Zenva offers the tools and resources to support your growth and help you achieve your game development aspirations. Start crafting the games of tomorrow, today!

Conclusion

As you’ve seen through this tutorial, mastering input events with modifiers in Godot 4 can significantly enhance the interactivity and sophistication of your game controls. The nuances of player input are what make games feel alive and responsive; they’re the difference between a good game and a great one. With the practical knowledge you’ve gained here, you’re well on your way to creating that immersive experience players crave.

However, don’t stop here! Continue expanding your game development skills with our Godot Game Development Mini-Degree. You’ll gain hands-on experience creating full-featured games across various genres, refine your coding proficiency, and build a portfolio that will stand out in the industry. Join us at Zenva, where we are committed to guiding you on your journey to becoming a game development expert. Let’s bring your imagination to life, and together, let’s create something extraordinary!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.