Targeting the Steam Deck with Godot
This tutorial guides game developers through the process of preparing a Godot project specifically for the Steam Deck device. It covers understanding Steam Deck hardware, handling input, optimizing game performance, and detecting the Steam Deck in the project, providing valuable insights for creating engaging games tailored for this exciting gaming platform. By Eric Van de Kerckhove.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Targeting the Steam Deck with Godot
25 mins
- Getting Started
- Understanding the Steam Deck Hardware
- Specs
- Considerations for Game Development
- Exploring the Project
- Running the Project
- Project Settings
- Detecting the Steam Deck
- Handling Input
- Input Map Setup
- Touchscreen Input
- Exporting Builds
- Game Performance
- Running the Linux Build
- Running the Windows Build
- Where to Go From Here?
Detecting the Steam Deck
Godot doesn’t have a built-in variable to determine if a device is a Steam Deck. What it does have is a set of functions that can read both the software and hardware information from the device. From this information, you can detect if the device is a Steam Deck if you know what to look for. To do that, you can add a script to the info label at the top left which will display the information and detect if your project is running on a Steam Deck.
First, select CanvasLayer ▸ Info ▸ MarginContainer ▸ SystemInfoLabel in the Scene dock.
Now attach a new script to the label, name it system_info_label.gd and place it in the scripts folder.
This should automatically open the Script screen and display the new script. To read the system information and add it to the label, replace the _ready
function with the following:
func _ready() -> void:
self.text = "" # 1
self.text += "OS: " + OS.get_name() + "\n" # 2
self.text += "Distro: " + OS.get_distribution_name() + "\n" # 3
self.text += "CPU: " + OS.get_processor_name() + "\n" # 4
self.text += "GPU: " + RenderingServer.get_rendering_device().get_device_name() + "\n" # 5
Here’s a summary of what this does:
- Clear the text of the label
- Use
OS.get_name()
to return the name of the operating system the build targets. Confusingly, this won’t always match the name of the actual OS. The\n
adds a new line at the end. -
OS.get_distribution_name()
returns the name of the distribution. On Windows (and Proton), this is “Windows”. On Linux, this is the name of the distribution, such as “Ubuntu” or “SteamOS”. - The
OS.get_processor_name()
function returns the name of the CPU. -
RenderingServer.get_rendering_device().get_device_name()
returns the name of the GPU.
Now press F5 to save the script and run the project. You should now see the system information in the info label
If you would export and run this project on your Steam Deck at this point, you’ll see that the system info is filled in correctly.
Here’s the result with a native Linux build:
And here’s the result with a Windows build:
I’ll cover how to export and run this project on the Steam Deck later on in this tutorial. For now, the most important thing to take away is what the Steam Deck reports as its CPU and GPU:
- CPU: AMD Custom APU 0405
- GPU: AMD Custom GPU 0405 (RADV VANGOGH)
Based on this information, you can detect if your project is running on a Steam Deck. To do so, add the following function to the system_info_label.gd script:
func _is_steam_deck() -> bool: # 1
if RenderingServer.get_rendering_device().get_device_name().contains("RADV VANGOGH") \
or OS.get_processor_name().contains("AMD CUSTOM APU 0405"): # 2
return true
else: # 3
return false
This function will return true
if the Steam Deck is detected, and false
otherwise:
- This is a function named
_is_steam_deck
which returns aboolean
value. - If the name of the GPU contains the string “RADV VANGOGH” or the CPU name contains the string “AMD CUSTOM APU 0405”, it returns
true
. - Otherwise, it returns
false
.
Now add this line to the _ready
function:
self.text += "Steam Deck: " + str(_is_steam_deck()) + "\n"
This will show true
or false
depending on if the project is running on a Steam Deck. Run the project again to see the result.
On an actual Steam Deck, this will be true
of course!
Here are some suggestions on what you can do with this information:
- Enable gamepad support
- Show button prompts and other graphics specific to the Steam Deck
- Automatically adjust performance settings to run optimally
- Move and resize UI elements for better readability
- Gather analytics to improve the project’s performance
Handling Input
The Steam Deck has input controls and a touchscreen. In this section you’ll learn how to get the input from the Steam Deck and use it in your project.
Input Map Setup
The input from the Steam Deck’s controller can be mapped in Godot as if you were using an Xbox controller.
To start off, take a look at the current actions in the input map by selecting Project ▸ Project Settings ▸ Input Map.
The actions defined in the input map are:
- accelerate
- brake
- left
- right
- switch_camera
For each of these actions, you’ll need to add a new gamepad event to support input from a game controller. Here are the mappings I’ll be using:
- accelerate : Right trigger
- brake : Left trigger
- left : Left analog stick left
- right : Left analog stick right
- switch_camera : Y button
You can change these mappings as you prefer, or add extra ones. To map a new event to an action, click the + button next to the action’s name.
Next, either press or move the input you want to bind to the action on your gamepad. If you don’t have a gamepad, you can select the event under Joypad Buttons or Joypad Axes. For the accelerate action for example, you’d press the right trigger.
Now click the OK button at the bottom left to confirm adding the event. You’ll now see that the event has been added to the input map.
Now do the same for the other actions until they all have gamepad events.
To test if the gamepad events are working, run the project again while using a gamepad.
Great! That’s all you need to do to support the Steam Deck’s controller. Next up is using the touchscreen.
Touchscreen Input
Although the Steam Deck has a touchscreen, it shouldn’t be the primary way to interact with your game due to the small screen size its lower sensitivity compared to a smartphone. However, you can add simple buttons or detect motion events as an optional feature.
As an example, you’ll be adding a button to the corner of the screen to switch the camera view.
To add the button, start by adding a Button node to CanvasLayer by right-clicking the CanvasLayer node and selecting Add Child Node. Next, search for “Button” in the search bar at the top, select Button and click the Create button to add it.
This should’ve added a new Button node below the CanvasLayer node.
Select this new button and rename it to CameraSwitchButton by right-clicking it and selecting Rename or by pressing F2. Now switch to the 2D mode to see selection box around the button at the top left. You may have to zoom in to get a better view.
At the moment, there’s not much to see. To change that, drag the camera_switch.png image from the sprites folder in the FileSystem dock onto the Icon field in the Inspector.
The button will now be a lot larger, with an icon in the middle.
To get the button to the top right instead of the top left, change its anchor preset to Top Right via the Anchor dropdown in the toolbar.
This moves the button to the top right as expected. To give it a small offset from the edges of the screen, hold down Shift and press the left arrow key on your keyboard followed by the down arrow key. This creates a few pixels of space from the edges.
To prevent the button from being pressed by accident when pressing keyboard or gamepad button, it’s best to disable the focus mode of the button. You can do this by scrolling down in the Inspector, expanding Focus under the Control section and selecting None from the Mode dropdown.
Great! All that’s left for this button is to hook up its pressed signal to the switch_camera
function of the CameraManager node. Switch to the Node tab in the Inspector and double-click the pressed() signal.
This opens a signal connection dialog window where you can choose a function to call when the button is pressed. Now select the CameraManager node and click the Pick button. This will open a list of functions that can be called.
Next, select the switch_camera
function and click the OK button.
Back in the signal connection dialog, click the Connect button at the bottom to finish the connection.
Here’s what the switch_camera
function looks like:
func switch_camera() -> void:
if birds_eye_camera.current:
behind_car_camera.current = true
else:
behind_car_camera.current = false
This toggles the active camera between the behind the car camera and the birds eye camera. With the button all set up, it’s time for another test drive!
Fire up the project again using F5 and test if the button works as expected.
The project is now finished! Time to test it on a real Steam Deck.