Input

What is a game without some interaction? Good thing LÖVE's API has various functions regarding input.

Input can be separated into three categories:

Keyboard #

With input we generally want to know three things:

isDown #

To check if a key is being hold down we use love.keyboard.isDown(key).

local x = 0

function love.update()
    if love.keyboard.isDown("right") then
        x = x + 1
    elseif x > 0 then
        x = x - 1
    end
end

function love.draw()
    love.graphics.rectangle("fill", x, 50, 100, 100)
end

The function accepts multiple arguments, so you can check if any of a list of keys is down.

function love.update()
    if love.keyboard.isDown("right", "d", "l") then
        x = x + 1
    elseif x > 0 then
        x = x - 1
    end
end

If we want to check if multiple keys are down at the same time we call the function twice and use and.

function love.update()
    if love.keyboard.isDown("right") and love.keyboard.isDown("lshift") then
        x = x + 1
    elseif x > 0 then
        x = x - 1
    end
end

"lshift" in the example above refers to the left shift button. Check out the KeyConstant page for a list of all the keys.

pressed / released #

Pressing and releasing a key are events, and to capture such events we use a callback. In this case the callbacks love.keypressed and love.keyreleased.

local score = 0

function love.draw()
    love.graphics.print(score, 42, 40)
end

function love.keypressed(key)
    if key == "up" then
        score = score + 1
    end
end

function love.keyreleased(key)
    if key == "down" then
        score = score - 1
    end
end

A problem with this is that our code can become very detached. What if deep inside our update function we want to know if a key was pressed? We can make a simple function to help with this.

Tip

You can also consider using an input library like baton.

local score = 0
local keysPressed = {}

local function wasPressed(key)
    return keysPressed[key]
end

function love.update(dt)
    if wasPressed("space") then
        score = score + 1
    end

    -- Reset the list of pressed keys.
    keysPressed = {}
end

function love.draw()
    love.graphics.print(score, 42, 40)
end

function love.keypressed(key)
    keysPressed[key] = true
end

textinput #

If you have a game where you can enter your name, it would be troublesome to use love.keypressed for it. You'd have to check if shift is being held down to decide whether the entered key is uppercase or not, for example.

Luckily, LÖVE also has the callback love.textinput. If the user used the combination that would type the dollar sign, then the text we get is the dollar sign.

local name = ""

function love.draw()
    love.graphics.print("Your name: " .. name, 10, 40)
end

function love.textinput(text)
    name = name .. text
end

function love.keypressed(key)
    if key == "backspace" then
        name = name:sub(0, -2)
    end
end

Mouse #

The mouse input API is very similar to that of the keyboard:

But instead of a string, we pass a number:

The mouse also has a position on the screen, which is passed along with the callbacks.

local circle = {
    x = 100,
    y = 100,
}

function love.draw()
    love.graphics.circle("fill", circle.x, circle.y, 20)
end

function love.mousepressed(x, y, button)
    if button == 1 then
        circle.x = x
        circle.y = y
    end
end

We can also use love.mousemoved to get the new position each time the mouse moved, or love.mouse.getPosition to always get the current position of the mouse.

With the callback love.wheelmoved we capture the event of the mouse wheel being used. A positive value indicates upwards movement.

local radius = 10

function love.draw()
    local x, y = love.mouse.getPosition()
    love.graphics.circle("fill", x, y, radius)
end

function love.wheelmoved(x, y)
    if y > 0 then
        radius = radius + 3
    elseif y < 0 then
        radius = radius - 3
    end
end

Joystick #

For controller input we use love.joystick. With the function love.joystick.getJoysticks() we get all the connected joysticks.

A joystick is any type of controller, like an Xbox controller or a PlayStation controller, but also a dance pad or a Wii Fit Balance Board. A standard controller, like the first two, are considered gamepads. These are joysticks who's buttons can be mapped to a common layout.

Note

Following the pattern in the image above, the A button refers to the bottom button of the four face buttons. This means that "a" refers to the X button on a PlayStation controller, and "x" refers to the square button. Check out the GamepadButton page for all gamepad buttons.

In this section we will focus on gamepads. We can check if a joystick is a gamepad by using Joystick:isGamepad().

Again, the gamepad input API follows a similar pattern:

If we want to check if player 2 is holding down the A button, we can use Joystick:getID() to check from which player the joystick is.

function love.update(dt)
    local joysticks = love.joystick.getJoysticks()

    for i=1, #joysticks do
        local id = joystick[i]:getID()
        if id == 2 then
            if joystick:isGamepadDown("a") then -- If not a gamepad, it will return false.
                print("Player 2 is holding down A!")
            end
        end
    end
end

With love.gamepadpressed and love.gamepadreleased we get the joystick that pressed it, along with the pressed button.

function love.gamepadpressed(joystick, button)
    print("Player " .. joystick:getID() .. " pressed the button " .. button)
end

function love.gamepadreleased(joystick, button)
    print("Player " .. joystick:getID() .. " released the button " .. button)
end

Axes #

Besides buttons, a gamepad also has control sticks and triggers. These have more than a pressed/non-pressed state, as you can move the control stick slightly to the right, or hold down the right trigger halfway.

The axes can be accessed using Joystick:getGamepadAxis(axis).

The axis argument needs to be a string.

function love.update(dt)
    local joysticks = love.joystick.getJoysticks()
    local player1 = joysticks[1]

    local x = player1:getGamepadAxis("leftx")
    local y = player1:getGamepadAxis("lefty")
    if x > 0.5 and y < 0.5 then
        print("Holding the left control stick in the upper right corner.")
    end

    local rightTrigger = player1:getGamepadAxis("triggerright")
    if rightTrigger > 0.3 then
        print("Slightly holding down the right trigger")
    end
end

Warning

With some controllers the control stick is never perfectly in the center. Take this into account when using axes, by using a threshold.

local x = player1:getGamepadAxis("rightx")
 
if x > 0 then
    -- Value could be something like 0.01
    print("Holding right apparently?")
end

if x > 0.2 then
    print("Definitely holding right! (Though slightly)")
end

The change in axis also has a callback: love.gamepadaxis.

function love.gamepadaxis(joystick, axis, value)
    if joystick:getID() == 3 then
        if axis == "lefttrigger" then
            if value > 0.5 then
                print("The left trigger of player 3 is pressed halfway.")
            end
        end
    end
end

Rumble #

Most modern controllers support rumble. We can set the rumble using Joystick:setVibration(left, right). You can set the vibration of the left and right motor seperately, but generally you'd want these to be the same.

function love.gamepadpressed(joystick, button)
    if button == "a" then
        joystick:setVibration(.5, .5) -- Vibrate on half strength.
    end

    if button == "b" then
        joystick:setVibration(1, 1, 3) -- Vibrate on full strength for 3 seconds.
    end
end

function love.gamepadreleased(joystick, button)
    if button == "a" then
        joystick:setVibration() -- Stop vibrating.
    end
end