3 minutes
Input Subsystem Redesign
Any game is driven by events. And the most foundational ones are related to controls. Player input is super-important since it steers the simulation. That is why the effort put into the input subsystem design pays off handsomely.
The Origin
Collider.JAM started with a very basic input system. All input events are captured by functions in /trap
. So /trap/keyUp(e)
captures all key up events, /trap/mouseMove(e)
- all mouse movements. Or maybe you want to capture an R keypress by creating trap/rDown(e)
.
It is simple, straightforward, and, more importantly, follows Collider.JAM opinionated conventions for names and placements.
Basically, you establish input handling by dropping a few .js
files in the /trap
folder. Very good for a simple prototype. But not good enough for more complex scenarios.
Handling Controllers
To address challenges of bigger games I’ve created a controller subsystem that builds upon the existing Collider.JAM foundation and handles more sophisticated cases, including input remapping and gamepads.
That system included a concept of “actions” and a way to map incoming gamepad/keyboard events into those actions. Then, there is a way to “bind” controls to a particular entity in the /lab
. All you have to do is to implement an act(action)
function with a switch to react to each particular event.
The Limitations
This system worked fine, but many games later I discovered its limitations. It is not easy to customize the mappings to gamepads (a bit easier for the keyboard though). Also, the idea of processing actions as integers turned out to be somehow limiting and in some places confusing. To improve readability, I always introduced global constants (e.g. UP = 1, LEFT = 2, DOWN = 3…). It is cumbersome and not flexible. Plus, there are cases when you would prefer to use human-readable strings for actions instead of constant numbers.
For a long time, I hesitated between two approaches - what must my actions be, constant-defined numbers like LEFT=2
or human-readable string literals like “left”?
Recently, I finally realized that the best approach is to merge those two in an input event object. That would allow us to use numeric values where convenient and string ones where clarity is the priority. Also, we can keep additional metadata there, like timings and the origin event objects.
So it is time to refactor the controller handling for Collider.JAM!
The Plan
We will introduce a new binding system with human-readable labels and the ability to remap. We will represent actions as objects. We will design for more complex scenarios, like the ability to store and restore entity bindings when switching between states.
And finally, the whole controller subsystem will be available as a collider patch within a standard Collider.JAM package.