TLbind
Contents
About
TLbind is a system which turns a mass of keyboard/joystick input into easy-to-use game-oriented controls. Making this divide also makes it easy to rebind controls, enable or disable keyboard or joystick input at will, and make digital and analogue input work easily together. It's goal is to make it easy to add professional-style configurable "2 sets of keys + optional joystick" controls to Love2D games.
It's under the ZLIB license.
Download
Contact
- Forum thread
- Taehl - SelfMadeSpirit@gmail.com
Setup
Procedural style
- Add TLbind.lua to your game's folder
- In love.load, add the code
TLbind,control = love.filesystem.load("TLbind.lua")()
- In love.update(), add the code
TLbind:update()
Object-oriented style
- Add TLbind.lua to your game's folder
- Assuming your player object is called "player", and you want its controls to be listed in player.control, use the code
player.controlOptions, player.control = love.filesystem.load("TLbind.lua")()
- In your player object's update function (or otherwise once per frame), call
TLbind:update()
- TLbind itself acts like an object, so you can give each player their own separate TLbind, if you so desire (could be handy for splitscreen)
FAQ
- Q) How do I know when a control is pressed?
- A) Whenever a control is pressed or held, control[control name] will be true. You could use it with a statement like
if control.up then
...
- Q) How do I change a control?
- A) To bind a "fire" control to the third button of joystick 0, for example, you would say
TLbind.joyBtns[0][3]="fire"
. From then on, control.fire would be true whenever Joy0 button 3 is pressed.
- Q) How do I know if the player has simply pressed the button, instead of holding it? What if I want to know when it's released?
- A) When any control is first pressed, control.tap[control name] will be true for one frame. Likewise, when it's released, control.released[control name] will be true for one frame. These would be used the same way you'd use a normal control -
if control.tap.jump then
. You can also use the control.controlPressed and control.controlReleased callbacks (see below).
- Q) What functionality does TLbind have?
- A) It separates controls (things your game cares about "jump", "left", etc.) and input (spacebar, joystick coordinates, etc.). This allows a game's controls to be easily configured at any time; lets a game have multiple inputs per control (or controls per input); and makes coding simpler. It makes it easy to bridge analogue and digital control; disable keyboard or joystick input easily; detection of taps instead of holding (no more "hold jump to bounce over and over the second you touch the ground"); and can optionally restrain analogue input (and associated digital input) to a circle (preventing the all-too-common "you run faster diagonally" bug)
- Q) Is it hard to use?
- A) I tried to make it as simple as possible, and the default bindings are an example of every feature: They demonstrate jump and attack controls bound to both keyboard and joystick buttons, and joint digital/analogue movement controls taking input from WASD, arrowkeys, joystick axes, and joystick hat at the same time. And configuring all that only takes six lines of code!
- Q) What's the difference between digital and analogue controls, and how do you make them work together?
- A) In TLbind, digital controls are keys or buttons, and are represented as either true or false. Analogue controls take input from joystick axes or balls, and are represented as a decimal between -1 and 1, with 0 being centered. TLbind lets you map an analogue control to two digital controls, which makes the analogue input trigger the digital controls and the digital input push the analogue control to -1 or 1. As an example: In the default bindings, pressing the joystick a little to the left would make control.horiz == -0.22191, control.left == true, and control.right==false.
Functions
TLbind:update
TLbind:update()
This updates the controls, and thus should be called once each frame. Please note that it has a colon, not a period.
control.controlPressed
control.controlPressed(c)
This callback works just like love.keypressed, except for controls (meaning it'll work properly with binding changes and joystick input). It gets called exactly once when a control is activated.
string c
- The name of the control that was pressed.
control.controlReleased
control.controlReleased(c)
This callback works just like love.keyreleased, except for controls.
string c
- The name of the control that was released.
Input types and configuration
Bindings are managed under TLbind (procedural example) or player.controlOptions (OOP example). A list of bindings are a table, grouped together by control, joystick number, etc.. For clarity, please refer to the following terminology:
- Control - an abstract, game-centric variable which will either equal true/false (for digital controls) or a number between -1 and 1 (analogue controls)
- Input - the signal a keyboard or joystick gives off when manipulated
- Bind - the link between input and controls. "When this input is triggered, set that control"
- Map - links an analogue control to two digital controls (example: By default, horiz is mapped to left and right)
TLbind.keys
This is for keyboard keys. You can have as many sets as you want (each set may contain one control, but any number of inputs). The outermost table holds different sets (tables), which contain bindings in the format TLbind.keys[set#][[[KeyConstant]]] = "control"
.
TLbind.keys = {
w="up", a="left", s="down", d="right", [" "]="jump", lctrl="attack", escape="menu",
up="up", left="left", down="down", right="right", z="jump", rctrl="attack",
}
TLbind.joyAxes
This is the list of joystick axes (the stick itself or gamepad thumbstick(s), but may also include rudders, etc.). It's in the form of TLbind.joyAxes[joystick#][axis#] = "control"
.
TLbind.joyaxes = { [0]={[0]="horiz", [1]="vert"} }
TLbind.joyBtns
This lists joystick buttons, in the form of TLbind.joyBtns[joystick#][button#] = "control"
TLbind.joyBtns = { [0]={[0]="jump", [1]="attack", [7]="menu"} }
TLbind.joyBalls
This is for any ball device a joystick may be sporting. Since these are rare, it's advisable to not make your game depend on using one. Their binds are in form of TLbind.joyBalls[joystick#][ball#] = {"x control", "y control"}
TLbind.joyBalls = { [0]={ [0]={"horiz","vert"}, [1]={"yaw","pitch"} } }
TLbind.joyHats
This table is for joystick hats (those mini-thumbstick things seen on some joysticks). Please note that they're digital, not analogue. They're bound in the form of TLbind.joyHats[joystick#][hat#] = {"l control", "r control", "u control", "d control"}
TLbind.joyHats = { [0]={[0]={"left","right","up","down"}} }
TLbind.maps
This table lists the analogue controls that should be mapped to and from digital controls. Using this, you can easily code for one type of input without having to worry about coding for the other type. They're created in the form of TLbind.maps[analogue] = {"negative digital", "positive digital"}
TLbind.maps = { horiz={"left","right"}, vert={"up","down"} }
TLbind.circleAnalogue
This feature restricts the movement of a pair of analogue controls to the inside of a circle, rather than the default square. Using this, you can avoid the classic "you move faster diagonally" bug very easily. A circle-analogue will reach about 0.7 when at a perfect 45-degree angle (but still reach a full 1 when straight). It's made in the form of TLbind.circleAnalogue[entry#] = {"analogue 1", "analogue 2"}
TLbind.circleAnalogue = { {"horiz", "vert"} }
A note about Xbox controllers
Microsoft has decided that Xbox controllers are the official gamepad for Windows, and as such, are the most common controller a player may have. Therefore, it's advisable to tailor your game's controls to work with them.
One important caveat about Xbox controllers: Both of their triggers (L2 and R2 for those of you more familiar with Playstations) are treated as ONE axis, rather than two buttons!