Full disclosure: I am working with Valve under contract on an ongoing technical writing project, including, but not limited to, this blog post. I am neither an official employee nor a representative/spokesperson for Valve, and any opinions or personal views expressed herein are my own.
Back at Steam Dev Days 2016, Valve graciously invited me to share the stage in explaining the Steam Controller to developers:
That talk was pretty general and big-picture, so I would like to follow it up with some more practical tips derived from my own experience adding native Steam Controller support to my own game, Defender's Quest: Valley of the Forgotten, and explain some of the many benefits you can get from doing the same.
One hesitation some people might have for adding native Steam Controller support is -- why go to all that work just to support one device, and a kind of weird one at that? Isn't it enough to just support XInput and be done with it? And what if the game is mouse/keyboard centric? Won't it be a pain to adapt it for controllers?
Today I seek to to answer all those questions and more.
The Input Revolution
The biggest news is that the Steam Controller initiative isn't just about one physical device any more.
When you hear the word, "Steam Controller", this probably comes to mind:
But did you know all of these are now "Steam Controllers"?
As of January 19th, the latest version of the Steam Client enables full Steam Controller Configurator support for not only the Valve Steam Controller, but also the Sony Dualshock 4, as well as all XInput devices, such as the XBox 360, XBox One, and XBox One Elite controllers, not to mention generic models manufactured by Logitech, et al.
Furthermore, there is already (experimental) support for rigging up DInput devices -- just look, I even managed to get this third-party Wiimote driver working* with the software!
*Just a proof of concept, your mileage may vary.
When you add native support for the Steam Controller API, you automatically get every supported device, a list that already comprises 95% of popular gaming input devices and will continue to grow over time.
And let's not forget these trusty stand-bys, which are also supported by the configurator:
(in the sense that you can assign mouse & keyboard inputs to devices supported by the Steam Controller, though not the other way around at the moment).
The configurator not only lets you use any supported device with just about any Steam game, it also gives players unprecedented control over how they control their games. There's no better example than this heart-warming reddit post from a disabled PC gamer:
But there's a lot to unpack here. What's this "Configurator" I just mentioned? Let's back up for a second and clarify what we're talking about.
These are the terms I'll use throughout this document, for clarity's sake:
Valve Steam Controller (VSC) -- the specific physical input device designed and manufactured by Valve commonly called the "Steam Controller." (You know, this thing).
Steam Controller Configurator (SCC) -- the software built into the Steam Client that allows for re-mapping input and controls in a bajillion different ways
Steam Controller API (SCAPI) -- the application programming interface that a developer uses to communicate directly with the controller in order to achieve "native Steam Controller support." This API is part of the Steam SDK.
Steam Controller Device (SCD) -- any physical input device that can be used natively with the Steam Controller Configurator. As of this writing, this includes the Valve Steam Controller, the Dualshock 4, and every XInput device, but not the Mouse & Keyboard.
XInput Device (XID) -- any input device that communicates using the XInput standard. In practice this is an XBox 360 or XBox One gamepad, or one of the many generic clones/knock-offs thereof.
Dualshock 4 (DS4) -- the standard controller that comes with the Playstation 4, designed and manufactured by Sony.
It's a gargantuan task to try to add direct support in your game for every single input device out there in a consistent, stable, and flexible way. The closest you can get right now is SDL, which I highly recommend for bringing a strong dose of sanity to conventional input, but the SCC takes things one step further.
Aside: my (personal!) hope is that the Steam Controller initiative will eventually become a new universal -- and open -- standard for PC gaming input. I'm definitely not speaking for Valve on this particular point as I have no idea what their long term plans are.
As I mentioned in my talk, the SCC is built on a few "big ideas:"
- The game should respond to actions, not inputs
- The user should choose their controls, not the game
- Input hardware should be more like software
The Steam Controller API is built around "actions." Mario jumps in response to a "jump" action from the API; the game has no knowledge of the "A" button. The player controls what means "jump" - it could be "A", "X", flicking a joystick upwards, whatever. The developer can (and should) upload a default configuration for the game, but the player can change it to whatever they want.
But it's more than just customization -- the player also gets features like turbo right out of the box. Even better, as new controllers become supported, more input methods become available without games having to add special support for them. For instance, if Valve were to somehow add support for original Nintendo Famicom controllers, the player could presumably trigger any in-game action by breathing into the microphone.
Here's my point. The Dualshock 4 features a gyro, but a common lament is that most PS4 games don't take advantage of it.
Why not? Probably because they'd have to add specific code to support it, and the XBox One doesn't have the same feature. Plus, design inertia keeps developers from sticking their neck out. This is a serious oversight, because twin analog sticks just don't have enough precision to match the fine-tuned aiming we're used to on PC.
But throw in gyro assist, and you can get pretty dang close. There's no better example of this than the new DOOM game:
Although DOOM doesn't use the native Steam Controller API, the Configurator is powerful enough to do some fun tricks in what's called "legacy mode," a backwards-compatibility fallback for games relying on conventional input.
In this screenshot you can see that each physical input on the DS4 controller is simulating some other device input -- in this case a mixture of conventional gamepad and mouse inputs. The right stick is bound to "Joystick Mouse" which means the game will receive low-level mouse movement inputs from it, and the internal gyro is also bound to mouse movement (The player in the above video is using a similar setup with the VSC, using the touchpad and gyro). The joystick sends coarse mouse motion, and the gyro sends fine mouse motion, and stacked together they create a seamless, high-precision aiming experience you simply can't reproduce with conventional analog sticks alone.
And here's the kicker -- DOOM doesn't have a single line of code to take advantage of this advanced aiming mechanism, it gets it for free thanks to the Steam Controller Configurator. And if you're using an XBox controller that doesn't have a gyro like the DS4 or the VSC? The default configuration just falls back to conventional stick aiming.
So, if the SCC can retrofit this awesome functionality into DOOM just via legacy mode, what's the point of adding official support for the native API? There's several reasons:
- Legacy support can only do so much
- In legacy mode, in-game icons can't match the player's configuration
- DOOM is a special case with flexible conventional input (other games can cause headaches for the configurator)
- The Native API saves you from writing your own (less powerful) input configuration screen
- The Native API lets you take full advantage of action sets
- Direct control of rumble, haptic pulses, light bar, etc, unified across all devices that support such features.
To touch on point 3, one of the chief headaches for legacy mode is when a game assumes the player will never need to use mouse/keyboard and gamepad inputs at the same time. If you mix and match these inputs in the SCC and the game doesn't cooperate, you'll see in-game input icons "flicker" back and forth between gamepad and mouse/keyboard hints, if they even work at all.
If your game makes proper use of the native API, you avoid all these headaches and create a much smoother user experience, and the best part is, it's easier than you think.
Let's move on to a practical example from my own experience: Defender's Quest.
I made some rookie mistakes early on by underestimating the new system:
- Making "gamepad" input an entirely separate global mode from "mouse & keyboard"
- Disallowing (or not expecting) simultaneous gamepad & mouse controls
- Using joystick-like analog actions where mouse-like actions would be better
- Not allowing mouse & keyboard and gamepad button glyphs to appear on screen at the same time
The common thread to all these mistakes was one deeply held and entirely false assumption:
Surely this can't substitute for a mouse!
So if there's one thing you take away from this article, it should be this:
Anything a mouse can do, the Steam Controller Configurator can do - and more!
This isn't to say the Steam Controller is going to best mouse/keyboard players in high-level competitions, but it is to say that if you have a button on the screen, in most cases, the player can just mouse over and just freaking click it. This works especially well with the VSC and the DS4.
You can get the same functionality with XInput devices via the SCC, but since those devices don't have a touchpad or gryo, the player will have to move the mouse around with just the analog sticks. For this case you might consider making sure you have conventional controller-friendly navigation actions available.
All that said, if your experience is anything like mine, you'll find manually supporting conventional controllers via XInput and other standards requires a lot more work than supporting the SCC -- especially if you want it to work cross-platform.
Now, onto the game itself. Defender's Quest makes for an interesting case because:
- It's a very PC-centric game genre (Tower Defense)
- Casual-level play requires lots of mouse-clicking
- High-level play requires precise mouse-clicking
- High-level play relies on a giant sea of hotkeys
All of which make it quite challenging to design a good user experience for conventional gamepads.
Let's go through each screen of the game, and see how they look when optimized for Mouse/Keyboard, Gamepad, and the Steam Controller API.
Basic Menu Navigation
In mouse/keyboard land, this is simple -- stick a bunch of buttons everywhere and let the player click on them.
Easy enough. I also like to stick tooltips on everything as an extra bit of polish and aid to understanding.
Now onto gamepad input.
Console RPG's have a well-worn standard for menu navigation: the "finger cursor":
This works best when options are laid out in a grid or list - press up/down/left/right to navigate, "A" to select, "B" to go back. Couldn't be simpler, and it's surprisingly adaptable to a wide variety of menus. We used this in Defender's Quest, and in accordance with The Five Golden Rules of Input as well as my own user testing results, we bound default finger cursor movement to the DPAD as well as the left and right analog sticks.
The other face buttons like X and Y are mapped to commonly used on-screen buttons so you can activate them with a single press:
Steam Controller API
Since most Steam Controller Devices can function just as well as a regular mouse, I could have just exposed an analog action that moves the mouse cursor and a digital action that clicks things, and left things at that. This would have been fine for supporting the VSC and DS4, but it would probably have been a bit awkward for XInput users.
Since I had already gone to the trouble of making a conventional gamepad menu, I went for the best of both worlds. When the Steam Controller API is in use the game uses "gamepad mode", but everything you see on screen is also clickable with the "mouse" whether that's an actual mouse or a Steam Controller Device.
Furthermore, whenever the game senses "mouse" movement, it hides the fixed-position menu finger cursor and instead shows the free-floating finger cursor which indicates mouse-like input, distinguished by a 45-degree tilt:
This lets the player fully control what input style is best for them -- they can navigate the menus with up/down/left/right actions, or using analog actions to move the finger pointer directly and click on the thing they want.
Also, see those button glyphs on the bottom of the screen? When using the SCAPI, they automatically match whatever device you're using. In the previous screenshot I was using a Valve Steam Controller, and so the game receives numerical constants from the API that correspond to VSC button glyph images. Here's what it looks like when using a DS4:
So just add all the right glyphs to your game, hook up a function to poll for an action's button glyphs, and you're done. But isn't Valve adding support for new controllers all the time? What happens if someone uses a new device my game doesn't have button glyphs for?
Got you covered:
Although my game does ship with its own DS4 button glyphs, I temporarily disabled them here to demonstrate a special feature. Here, the game calls the
GetDigitalActionOrigins() function, which returns the physical inputs that the player has chosen to bind to that particular digital action (IE, "press X for options").
However, in this example the game receives a value it doesn't recognize because that value wasn't defined when the game was compiled, and thus it doesn't know what image to load. This case is easy to detect in code, at which point the game calls the
GetGlyphForActionOrigin() function as a fallback and passes in the unknown enumeration value. This returns a path to a suitable image file for the unknown glyph by grabbing it directly from the Steam Client's install directory:
In other words, it's a forwards-compatible polyfill.
This is a super convenient function whose only downside is that the glyph might not perfectly match your game's art style -- a much better outcome than broken image glyphs, or even worse, a crash! And you can always push an update with new custom glyphs on your own schedule.
Now, let's take a look at the default menu navigation configuration:
First of all, we're in the "Menu Controls" action set. As I said in the talk, all actions are divided into different "action sets", and this is the one that governs basic menu navigation. Action sets let you organize related actions into distinct groups that are only active at certain times so you don't crowd the input space with always-on actions that are only used some of the time.
You'll notice that both the right touch pad and the gyro are bound to the "move finger cursor" action -- I'm using the same "stacked input" method I mentioned earlier with DOOM. If we go into the gyro settings we see this: