#21 Input management


Welcome to the twenty-first devlog!

Today I want to talk about input management: how I made the game playable for any controller and keyboard (at most two players on the keyboard, though). Basically, this will be a short tutorial on using the Input Map (from Godot Game Engine) to seamlessly allow controller and keyboard players.

 

Fixed input schemes

There are quite a lot of games that use “fixed” input schemes. These games say: “keyboard players are ALWAYS the first and second player – if there are controllers, they will be pushed to another spot when a keyboard logs in”

Other games just support three possible input schemes:

  • “4 controllers”
  • “1 keyboard, 3 controllers”
  • “2 keyboard, 2 controllers”

I think this is way too rigid and would only make the code very messy.

I decided to allow devices to be activated in ANY order and belong to ANY player. Fortunately for me, this was easier than I thought :p

 

Godot input management

Godot works with an “Input Map”. You can create a certain action (like “jump”), and then assign keys/controller buttons/whatever to this action.

HOWEVER, you can only assign a certain action to a single specific device, or to all devices.

For example, if I want to allow any player to restart the level, I can just say:

  • ACTION = “restart_level”
  • DEVICES = “all devices”
  • BUTTON = <whatever I want to use for restarting>

The whole idea of controllers, however, is that everyone controls their own individual character. As such, I need to create a unique action for each device.

For the first controller, for example, I need to do this:

  • ACTION = “jump0”
  • DEVICE = “device 0”
  • BUTTON = “A”

For the second, I need to create the action “jump1”, and so forth.

It was roughly 20-30 minutes of boring work to create all these actions and link them to the right buttons, but then it worked flawlessly.

 

A screenshot of (part) of my Input Map.

Issue #1

Device 0 … might not actually be the first controller you plugged in. The devices are ordered by the system itself, and you might be playing with device 1 and device 4, just because the system has decided to assign those IDs.

The game needs a way to link a specific DEVICE to a specific PLAYER.

For this, I created a global variable (accessible in all scenes) called control_map.

It works like this:

  • Any time a device presses a button, the global script checks if this device was already registered or not. (It loops through the control_map and checks if any device ID matches.)
  • If not, it adds another player, and saves the device number at that index.
    • Let’s say you have one player currently, and a second player logs in with device #3. Then control_map[1] = 3. (Lists start at 0 in code, that’s why second player = 1.)
  • When the game actually starts, each player is assigned their device. Using this number, it caches all the actions it has:
    • Player 1 just adds a “0” to the end of all possible actions: “jump0”, “throw0”, etc.
    • Player 2 does the same, but appends a “1”, and so on.
  • This way, as you play the game, each player only listens to its own actions.

This is basically all the code that's needed to connect the right device with the right player. (Note that the action list is not complete - it's only the actions that have currently been implemented. ):

func set_controller(device_num):
    var actions = ["right", "left", "up", "down", "throw", "jump", "mount"]
    for action in actions:
         control_table[action] = action + str(device_num)

 

The variable `control_table` is a dictionary saved on the player itself. This loop simply adds the device number to the end of each action string, so anytime we ask the program to check for e.g. jumping, it automatically checks "jump0" for the first player, "jump1" for second, etc.

Checking for input in Godot is as simple as `Input.is_action_pressed(<name of action here>)`  There's also `is_action_released` and `is_action_just_released`, if you need it.

Issue #2

This works great. But … only for controllers. How do we add keyboard players?

As you might have noticed: the device numbers are always POSITIVE. The computer will never say: “this controller is device -1”

This means I can use the negative numbers for the keyboard players! The first keyboard player is -1, the second keyboard player is -2.

So I added some more actions to the input map, like “jump-1” and “jump-2”, and all the other actions.

And that’s all that was needed to allow keyboards to work! The order of the devices, or their ID, doesn’t matter at all. The control_map converts them when needed, and that’s all there is to it.

 

Controller login

At first, I thought about allowing players to log in or leave during a level. Then I realized this was a really stupid idea: levels are only a few minutes and can change based on player count. Why would I need to allow players to be added or removed at any time?

So, controllers can be logged in during the campaign screen and level select screen, and not during a level (or at the game over screen).

When adding keyboard players, the system simply checks how many keyboard players are already present, and changes the text (or required input to log in) based on that. The first player needs to press ENTER, the second needs to press A. (I couldn’t allow “press any button” for keyboard, because there still needed to be a way to control or quit the game. And it would log in both keyboard players at the same time, because they would use the same button.)

There’s currently no way to “log out” a controller. I know many games log in controllers by pressing the “A” button (I’m always giving Xbox examples, sorry, I just know that one off the top of my head), and allow controllers to log out again by pressing the “B” button.

In my experience, however, this was always just a nuisance. I’ve never had to consciously log out a controller (why would you?), but I’ve accidentally logged myself out MANY times. That’s why I’m currently not supporting that system. Of course, it might change later.

 

Conclusion

A bit of a boring devlog, without pictures or nice videos of level design. Nevertheless, I hope you learned something from it! It took me some time to figure out the Godot input system, as it has its quirks, but now that I understand it you can actually make things work pretty easily.

Get Package Party

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.