Joysticks are kind of jerks.
Now I know what you're thinking. You may even be looking nervously at the controller sitting on your desk right now, feeling thoroughly guilty after musing upon that statement for an extended period of time.
Don't get me wrong though. Controllers are cool. I like those guys. It's joysticks
that are jerks.
What's the difference, you ask? This is best answered with an example from a support inquiry that I've actually received multiple times for multiple games:
Gamepad: Microsoft Microsoft® 2.4GHz Transceiver v6.0
Number of axes: 37
Number of hats: 0
Number of buttons: 57
For those who don't know, this particular device looks something like this:http://www.flibitijibibo.com/ffffffriday/tttttthanksgoogle.jpg
I wonder if all the controls are on the other side?
This is a problem that's been around forever. Some brain-genius decided that devices like these, of all the things they could possibly be interpreted as by the OS, should be a joystick
. Don't think too much about this, they certainly didn't!
But let's say this isn't a problem. Maybe everyone remembered to take their brain medicine and the only things we ever see from the joystick subsystem are actual controllers. This would at least fix the crashes that you often get, but then there's the issue of actually setting up bindings for everything.
Even in the early days of my porting career it was apparent to me that this needed to be crowdsourced. I've tried this before...http://pcgamingwiki.com/wiki/Vessel#Controller_Input
... but it gets ugly fast
. It's also really crash-prone, too. If only there was a way to safely standardize controls for a particular setup and oh wait SDL2 has this doesn't ithttps://wiki.libsdl.org/CategoryGameController
When Valve started picking up Linux support for Steam and their games, one of the first things that was contributed was the SDL_GameController subsystem. Written on top of the low-level SDL_Joystick subsystem, this wrangles everything into the 360 controller format, using a database found within SDL2 internally and from Steam Big Picture mode. Game developers can also provide their own database of bindings, if they choose to do so. This ended up being such a solid part of SDL2 that Valve now uses this for Windows titles as well, as it provides both XInput/DirectInput support in a single API and lets them take advantage of the work they put into Big Picture mode's controller work.
Much like the faux-backbuffer stuff I talked about last week, I've used this in every game since updating to SDL2. FNA uses this by default, and falls back to some low-level joystick stuff I wrote before the SDL2 update.
That's a bit of a tradeoff with GameController. Unlike Joystick, where it just interprets any old hardware that it finds (for better or for worse), GameController only picks up what it knows about already. The hole that this leaves is mostly for non-Steam customers who have controllers not recognized by any database, but this is something I may end up resolving, either for VVVVVV or for FNA. But, so many games are now using this that it really did standardize things pretty well. Even with 15+ games on my plate using this, I very rarely get any inquiries about the fallback support. Of course, I do still try and keep it all documented:http://pcgamingwiki.com/wiki/Engine:FNA#Joysticks
The point is, adding support for new input methods is a LOT of work. Keep in mind that everything I've been talking about is purely technical... there's lots of design problems to be had as well. I'd like to point you to the SDL2_GamePad in FNA:https://github.com/flibitijibibo/MonoGame/blob/monogame-sdl2/MonoGame.Framework/SDL2/Input/SDL2_GamePad.cs
This is the file that handles all
of the controller support for my XNA ports. Note, these games that I port are A: finished products, and B: using this API that I cannot change. A lot of the work that goes into this is not just implementing what's there, but trying to expand upon the massively restrictive controller support found in XNA (and it is restrictive - XNA only supports the 360 controller and nothing else). Having to design all these things to make the controller support even the slightest bit acceptable while not affecting the design of both the XNA4 API as well as the game using
XNA4 has been pretty tough.
But now let's look at VVVVVV, which I've managed to not talk about for nearly two pages of raw text. With that, I bring up my usual disclaimer:DISCLAIMER: All of the work described here is a WIP, and is NOT FINAL!
To keep things interesting, let's change the format a bit and go through a pseudo-live experience of modern controller support, using the WIP joystick support in the VVVVVV revision I got. (Sorry, Simon.)http://www.flibitijibibo.com/ffffffriday/ggggggamepad21_1.png
Oh, hey, Simon has a menu and everything! But boy I sure hope the rebind doesn'thttp://www.flibitijibibo.com/ffffffriday/ggggggamepad21_2.png
Simon no D:
I hate this way of binding buttons, especially for controllers. It just doesn't work. Depending on the gamepad, the wrong button gets interpreted, or an axis gets interpreted because its default isn't 0, or some other stupid nonsense that makes these menus just the worst thing. And you've not even bound your controls yet.
And god help you if that button you just tried to rebind affects menu navigation. Don't you just love when you, say, rebind the back button, and attempting to rebind does any of the following at random:
- Backs out and doesn't bind the item
- Binds the item and backs out, not saving changes
- Binds the item and backs out, saving changes, and oh I'm sorry did you not bind "menu select" yet?
- Binds the item and mixes with either another binding or a hardcoded bind options, mixing up controls and making it impossible to rebind without clumsily breaking everything like a drunk in a antique shop and god ngf-WHY IS THIS SO BROKEN AHHHNGNGGFFFFFF RAHHH RIP AND TEAR EVERYTHING
This. Doesn't. Work. I've seen this in SO many games, many that I've worked on even, and it's a complete disaster every time. I'd rather just edit a config file. Of course, in a console setting that doesn't work either... so what do you do?
The common solution seems to be just not having custom controls, and for VVVVVV, I sort of considered that... the game only has 3 buttons, so we may as well just use up all the buttons and present an image for controls, like a lot of games do these days. Neither of us really liked that idea though, and it probably would have taken more work than just making a binding menu that didn't suck.
To my luck, making a menu that didn't suck was pretty easy. Here's a sample of how the rebinding works in the current revision of VVVVVV:https://vine.co/v/MXhQdq9IIIr
And a screenshot:http://www.flibitijibibo.com/ffffffriday/ccccccontrollerwip.png
Here's how it works:
First off, analog sticks and d-pads are constant. Up/Down/Left/Right are locked values, and SDL_GameController can easily wrangle these for us. There's a good chance I'll add the option to invert axes, but for now, we've got working movement.
For buttons, the instant you enter the three binding options, ALL button input is completely overridden and now only affects what the bindings lists are. Absolutely nothing happens with these button presses except for changing the bindings, until you exit the list. Only when you leave that section of the menu do the buttons do anything else at all, period.
This is a drastically better method of rebinding controller mappings in every single way possible. It not only makes the binding process simpler and more reliable, but it's actually so simple to use that mistakes essentially have no penalty.
Let's think about that back button example again. Let's say you get all your buttons bound, you've got everything you want (and it will
work because again, input only affects the bindings here!), and now you're ready to leave. You might be inclined to hit the back button right away, but because you're still in the button setup options, it will actually rebind the back button to whatever you've got selected. What's the worst-case scenario here? That you may have rebound your back button to something else? By this point, you've almost certainly learned how this works, so you just rebind the back button to what you really wanted, then just exit the menu using the proper exit option. Sure, you may have had to do this, but how long do you expect that will take... 2, maybe 3 seconds to process in your head? It's a whole lot better than doing an incorrect binding and spending 5 minutes making a battle plan to escape the personal hell you just created for yourself.
And, of course, all of this is editable in the config file as well.
This, being a brand new feature, isn't entirely complete yet. As I mentioned before, I will probably add a way to invert axes, and I'm sure there are other options I haven't considered yet, but getting SDL_GameController hooked up and making a menu that didn't totally suck were the top priorities for this feature. If there's something you're worried I'll miss, feel free to poke me.
Next week, I'll be taking a break from all this portable stuff and digging into the good ol' days of porting stuff again. Even crazier, I'm actually adding
a dependency to the game to do this... what could it be?!