Given that you’ve already those steps, we’re going to begin by adding our own initialization code to our Steam autoload.
The SteamControllerInput.init() function needs to be called afterSteam.initInput() and Steam.enableDeviceCallbacks().
Here we’re creating the init function that gets called in our Steam autoload, and connecting to the Steam.input_device_connected and Steam.input_device_disconnected signals to handle when a player connects or disconnects their controller.
You need to wait until a controller has been connected before you can get the action and action set handles.
If you try to get them before a controller has been connected GodotSteam will return 0 for all handles.
⚠️
Though, as I was writing this I’m still encountering handles returning 0 even after a controller has been connected,
so this feels like a bug, similar to the controllers not responding if you pause your game via get_tree().paused = true.
Hopefully these will both be addressed soon.
Now that a controller is connected, we can get the action set and action handles.
In this example .vdf file I have a single action set called GameControls and a number of actions defined within it.
Now we iterate over the action names and get the handles for each action, using the Steam.getAnalogActionHandle and Steam.getDigitalActionHandle functions depending on the input type.
Since we’ll be supporting both Steam Input and a keyboard via GodotInput,
we can specify -1 as the device ID for the keyboard, and add any detected controllers to the list of device IDs.
But now that we have controllers, how do we use them?
These wrappers expect a device handle to be passed in. If the device handle is less than 0, it will fall back to the default Input functions, so I use -1 to indicate a keyboard.
Get the strength of an action. This is useful for analog inputs such as a single axis of a joystick, or a trigger.
Steam’s getAnalogActionData function returns a Vector2 with the x and y values of the action, but the y value is always 0 for single axis inputs such as triggers. By only returning the x value we can emulate Godot’s get_action_strength function.
get_vector is largely used for movement, and is useful for things like joysticks or dpads.
We need to invert the y axis because Steam’s y axis is inverted from Godot, but otherwise emulates Godot’s get_vector function.
By default, Godot gives a really nice set of Input functions that allow you to check if an action was just pressed or just released this frame. This can be very useful for ensuring that you only perform an action once per press, or for tracking how long an action has been held for.
Unfortunately, Steam Input doesn’t give us that functionality, so we need to implement it ourselves.
Let’s start by adding a new dictionary to store the state of each action at the top of our file:
In order to use that dictionary, we’ll need a function to get the action state for a given device and action.
If the action state doesn’t exist yet, we’ll create it with the default values, setting held to false and press_frame and release_frame to -1.
Though that won’t be useful without a way to set the action state!
In order to set the action state, we’ll need to know the current state of the action, and the current frame.
We can then compare the current state to the previous state to determine if the action was just pressed or just released.
By tracking the frame that the action was pressed or released we can easily implement our missing input methods!
To check if the action was just pressed we can use the Steam.getDigitalActionData function to check if the action is currently held.
But, if we stop there we will have failed to track the press frame, so we’ll need to call our set_action_state function to update the state of the action.
In order to check if the action was just released, we need to check if the action is not currently held, and if the release frame is the current frame.
Every frame my player script uses the input script to check if the player should move, jump, etc.
I’ve got plans to put more detail in a few areas but let me know if something is unclear or you’re trying to do something I haven’t covered here.
I’m in the GodotSteam discord as furd, feel free to talk to me there.
I’ve got a few things still in the works but by assigning a deviceId to your player you can use this to check the input for a specific player.
Hi! I'm Matt, a software engineer and artist based in the Central Coast of California.
You can chat with me on Discord,
see some of my work on GitHub or Instagram.