The code I wrote for key binding in LibGDX looks pretty easy to integrate into other codebases – it took about an hour to get it working in Untitled Game, and most of that was fiddling with the options menu – so I thought I’d put it up on my Bitbucket in case anyone wanted to use it.
Normally, LibGDX uses an “InputProcessor” to send input events to your game code. One of your classes, maybe the Screen or Level or even PlayerShip class, implements the InputProcessor interface and has methods like keyUp() and keyDown(). These methods give you an integer keyCode so you can tell the W key apart from the S key. Then, in your class, you do something if W is pressed, and something else if S is pressed. Naturally, that’s a lot of hardcoded controls, and most people want the ability to change the controls – especially if they have a weird or foreign keyboard layout.
There are two good ways (that I can think of right now) to implement key binding: Using a data set like a HashMap that gets checked every time you receive an input event, or through another layer of abstraction that catches input events and distributes command events of its own.
I initially wrote a “dumb” class that stored a HashMap (the best data structure) of key bindings and contained no real logic of its own. I eventually found that I was writing a lot more cruft in my game code and in the options menu than I would have liked: lots of lookups in PlayerShip (my InputProcessor) checking which command just got pressed, and a lot of awkward state-handling code in my options menu (every button had a check for whether the game was currently trying to rebind a key, or whether we could actually use the next mouse event).
So I wrote CommandManager, which takes all that cruft and stuffs it in its own class where it belongs. CommandManager is an InputProcessor, so it takes care of the input events, and sends “command events” out to my PlayerShip class. Instead of implementing keyDown() and comparing it to WASD, or getting keyDown() and checking against a HashMap, I implement CommandDown() and check against “MoveUp” and “MoveDown”. And, crucially, the code to rebind an event is two lines in the options menu with no awkward state-checking in the rest of the code:
These lines set the CommandManager into the “checking for a new key binding” state and let it take over control. The “this” parameter refers to the MainMenu screen, another InputProcessor, which normally has control while it’s displayed – the CommandManager will return control to it as soon as it gets the next key to bind.
Finally, CommandManager can write commands out to a newline-delimited string, and accept commands in the same format in its constructor, which makes for very easy saving to LibGDX Preferences or a keys.ini file.
The code’s on my Bitbucket if you’re interested: https://bitbucket.org/EF314159/commandmanager