Home

Awesome

For anyone coming here from awesome-love2d (or anywhere else), if you need an input library, give Baton a shot first! It's the successor to Tactile and is much better, at least in my opinion.

Tactile

Tactile is an input library for LÖVE that bridges the gap between different input methods and types. In Tactile, there is no distinction between buttons and analog controls - controls are both buttons and axes at the same time.

Control = {
  Horizontal = tactile.newControl()
    :addAxis(tactile.gamepadAxis(1, 'leftx'))
    :addButtonPair(tactile.keys 'left', tactile.keys 'right'),
  Fire = tactile.newControl()
    :addButton(tactile.gamepadButtons(1, 'a'))
    :addButton(tactile.keys 'x')
}

function love.update(dt)
  Control.Horizontal:update()
  Control.Fire:update()

  player.x = player.x + player.speed * Control.Horizontal() * dt
  if Control.Fire:isDown() then
    player:shoot()
  end
end

Table of contents

Overview

Tactile has two types of objects:

Controls

Controls contain a series of detectors and use them to act as both a button and an axis. The most important function is Control:getValue, which runs through all of the detectors in order and uses them to calculate a value between -1 and 1.

Controls also act as buttons, so they can be "down" or not "down". They're considered to be "down" if Control:getValue is a non-zero number. Furthermore, controls can be "down" in a certain direction, meaning Control:getValue is less than -deadzone or greater than deadzone. They also keep track of whether they were pressed or released in the current frame.

Examples

That was all very abstract. What does this mean? Well, here are some examples of common ways to use Tactile. For these examples, let's assume that we've set up the controls like this:

Control = {
  Horizontal = tactile.newControl()
    :addAxis(tactile.gamepadAxis(1, 'leftx'))
    :addButtonPair(tactile.keys('a', 'left'), tactile.keys('d', 'right')),
  Vertical = tactile.newControl()
    :addAxis(tactile.gamepadAxis(1, 'lefty'))
    :addButtonPair(tactile.keys('w', 'up'), tactile.keys('s', 'down')),
  Fire = tactile.newControl()
    :addAxis(tactile.gamepadAxis(1, 'triggerleft'))
    :addAxis(tactile.gamepadAxis(1, 'triggerright'))
    :addButton(tactile.gamepadButtons(1, 'a'))
    :addButton(tactile.keys 'x')
}

First, let's think about movement. This is the perfect time to use controls like axes. The Horizontal and Vertical controls have the left analog stick, arrow keys, and WASD mapped to them, so you can easily do something like this:

player.x = player.x + Control.Horizontal:getValue() * player.speed * dt
player.y = player.y + Control.Vertical:getValue() * player.speed * dt

Since Control:getValue() always returns a number between -1 and 1, the player will move at a speed and in a direction that makes sense given the input.

Now let's think about shooting. This is something that's handled by a button input. We'll use the Fire control:

if Control.Fire:isDown() then
  player:shoot()
end

That's all we have to do! The Fire control has the X key, A button on the gamepad, and left and right triggers mapped to it. If X or A are pushed down, or if either trigger is pushed down more than halfway, the Control.Fire will register as being pushed down.

One more example: menu controls. This is the sneaky one! It's obvious to use Horizontal and Vertical as axes and Fire as a button, but for menus, we need to use the analog stick and the arrow keys as button presses to move a cursor around. But since controls are both axes and buttons, this is already set up for us. We'll use the dir argument of Control:pressed to detect button presses in certain directions.

if Control.Horizontal:pressed(-1) then
  -- move the cursor to the left
end
if Control.Horizontal:pressed(1) then
  -- move the cursor to the right
end
if Control.Vertical:pressed(-1) then
  -- move the cursor up
end
if Control.Vertical:pressed(1) then
  -- move the cursor down
end

Usage

Place tactile.lua somewhere in your project. To use it, do:

local tactile = require 'path.to.tactile'

API

Controls

Control = tactile.newControl()

Creates and returns a new control.

Controls have the following properties:

Control:addAxis(f)

Adds an axis detector to the control.

Control:addButton(f)

Adds a button detector to the control.

Control:addButtonPair(negative, positive)

Adds a button pair detector to the control, which is generated from two button detectors. The negative button detector will be mapped to -1, and the positive button detector will be mapped to 1.

Control:getValue()

Returns the current axis value of the control. As a shortcut, you can simply call Control(), which returns Control:getValue().

Control:isDown(dir)

Returns whether the control is down or not. The control is considered to be down if its absolute value is greater than the deadzone.

Control:pressed(dir)

Returns whether the control was pressed this frame.

Control:released(dir)

Returns whether the control was released this frame.

Control:update()

Updates the state of the control. Call this on all of your controls each frame. Sorry you have to do this. :(

Detectors

Since detectors are just functions, you could write your own (and in some cases, you might want to). However, Tactile provides built-in detectors that should cover all the common use cases.

tactile.keys(...)

Returns a button detector that returns true if any of the specified keys are down.

tactile.gamepadButtons(num, ...)

Returns a button detector that returns true if any of the specified gamepad buttons are held down.

tactile.gamepadAxis(num, axis)

Returns an axis detector that returns the value of the specified gamepad axis.

License

Tactile is licensed under the MIT license.

Copyright (c) 2016 Andrew Minnich

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.