2
-- This represents a single gamepad connected to the user's computer. This offers the
3
-- usual functions to check on the status of buttons; you can also inspect other
4
-- controls, like analog joysticks, by checking properties like <axes> and <hats>.
5
-- (Incidentally, a hat is used for things like a digital control pad.)
7
-- Normally, gamepad buttons are indexed by number. This class also adds virtual buttons
8
-- named 'left', 'right', 'up', 'down'. This consults the first two analog axes
9
-- and the first hat of the gamepad (if they exist) to set these.
11
-- A gamepad is only recognized if it is plugged in when LOVE starts up. There's no way
12
-- to tell if the user has unplugged it after that; it just acts inert. A gamepad object
13
-- with no connected hardware at startup will exist and respond to calls like <pressed()>,
14
-- but it will always return false. You can tell it's unplugged because its active property
15
-- will be false, and its name will always be 'NO DEVICE CONNECTED'.
20
Gamepad = Sprite:extend
23
-- The index of the gamepad, starting at 1.
26
-- The name of the gamepad, e.g. "XBox Controller".
29
-- The number of available axes, e.g. for analog controls.
32
-- The number of available balls.
34
-- Property: numButtons
35
-- The number of available buttons.
38
-- The number of available hats, e.g. digital movement controls.
41
-- The state of all analog axes on the gamepad, indexed by number.
42
-- Values range from -1 to 1, where 0 is completely neutral.
45
-- The amount of motion by a each ball on the gamepad, indexed by number.
46
-- Not sure what the range of values is here.
49
-- The state of each hat on the gamepad, indexed by number. Each one has
50
-- one of these values: https://love2d.org/wiki/JoystickConstant
53
-- Any motion by an analog control (from 0 to 1) less than this value is
54
-- ignored when simulating digital controls.
58
-- private property: _thisFrame
59
-- what keys are pressed this frame
60
-- if you are interested in this, use allPressed() instead
64
-- private property: _lastFrame
65
-- what buttons were pressed last frame
69
new = function (self, obj)
70
obj = self:extend(obj)
71
assert(type(obj.number) == 'number', 'must set a gamepad number')
77
if obj.number <= love.joystick.getNumJoysticks() then
78
if not love.joystick.isOpen(obj.number) then love.joystick.open(obj.number) end
79
obj.name = love.joystick.getName(obj.number)
80
obj.numAxes = love.joystick.getNumAxes(obj.number)
81
obj.numBalls = love.joystick.getNumBalls(obj.number)
82
obj.numButtons = love.joystick.getNumButtons(obj.number)
83
obj.numHats = love.joystick.getNumHats(obj.number)
85
-- set initial values for axes and balls
86
-- hat values are strings so nil comparisons are safe
88
for i = 1, obj.numAxes do
92
for i = 1, obj.numBalls do
93
obj.balls[i] = { x = 0, y = 0 }
96
obj.name = 'NO DEVICE CONNECTED'
103
love.joystickpressed = Gamepad._dispatchPress
104
love.joystickreleased = Gamepad._dispatchRelease
105
if obj.onNew then obj:onNew() end
110
-- Are *any* of the buttons passed held down this frame?
113
-- button numbers passed as individual arguments
118
pressed = function (self, ...)
119
local buttons = {...}
121
for _, value in pairs(buttons) do
122
if self._thisFrame[value] then
130
-- Method: justPressed
131
-- Are *any* of the buttons passed pressed for the first time this frame?
134
-- button numbers passed as individual arguments
139
justPressed = function (self, ...)
140
local buttons = {...}
142
for _, value in pairs(buttons) do
143
if self._thisFrame[value] and not self._lastFrame[value] then
152
-- Are *all* of the buttons passed not held down this frame?
155
-- button numbers passed as individual arguments
160
released = function (self, ...)
161
local buttons = {...}
163
for _, value in pairs(buttons) do
164
if self._thisFrame[value] then
172
-- Method: justReleased
173
-- Are *any* of the buttons passed released after being held last frame?
176
-- button numbers passed as individual arguments
181
justReleased = function (self, ...)
182
local buttons = {...}
184
for _, value in pairs(buttons) do
185
if self._lastFrame[value] and not self._thisFrame[value] then
193
-- Method: allPressed
194
-- Returns all buttons currently pressed this frame.
200
-- string button descriptions; if nothing is pressed, nil
202
allPressed = function (self)
205
for key, value in pairs(self._thisFrame) do
206
if value then table.insert(result, key) end
209
return unpack(result)
212
-- Method: allJustPressed
213
-- Returns all buttons just pressed this frame.
219
-- string button descriptions; if nothing is just pressed, nil
221
allJustPressed = function (self)
224
for key, value in pairs(self._thisFrame) do
225
if value and not self._lastFrame[key] then table.insert(result, key) end
228
return unpack(result)
231
-- Method: allJustReleased
232
-- Returns all buttons just released this frame.
238
-- string button descriptions; if nothing is just pressed, nil
240
allJustReleased = function (self)
243
for key, value in pairs(self._thisFrame) do
244
if not value and self._lastFrame[key] then table.insert(result, key) end
247
return unpack(result)
250
buttonPressed = function (self, button)
251
self._thisFrame[button] = true
254
buttonReleased = function (self, button)
255
self._thisFrame[button] = false
258
endFrame = function (self, elapsed)
259
-- move button values to the previous frame
261
for key, value in pairs(self._thisFrame) do
262
self._lastFrame[key] = value
267
for i = 1, self.numAxes do
268
self.axes[i] = love.joystick.getAxis(self.number, i)
271
for i = 1, self.numBalls do
272
self.balls[i].x, self.balls[i].y = love.joystick.getBall(self.number, i)
275
for i = 1, self.numHats do
276
self.hats[i] = love.joystick.getHat(self.number, i)
279
-- simulate digital controls
281
self._thisFrame['up'] = false
282
self._thisFrame['down'] = false
283
self._thisFrame['left'] = false
284
self._thisFrame['right'] = false
286
if self.numHats > 0 then
287
local hat = self.hats[1]
290
self._thisFrame['up'] = true
291
elseif hat == 'd' then
292
self._thisFrame['down'] = true
293
elseif hat == 'l' then
294
self._thisFrame['left'] = true
295
elseif hat == 'r' then
296
self._thisFrame['right'] = true
297
elseif hat == 'lu' then
298
self._thisFrame['up'] = true
299
self._thisFrame['left'] = true
300
elseif hat == 'ru' then
301
self._thisFrame['up'] = true
302
self._thisFrame['right'] = true
303
elseif hat == 'ld' then
304
self._thisFrame['down'] = true
305
self._thisFrame['left'] = true
306
elseif hat == 'rd' then
307
self._thisFrame['down'] = true
308
self._thisFrame['right'] = true
312
if self.numAxes > 1 then
313
local xAxis = self.axes[1]
314
local yAxis = self.axes[2]
316
if math.abs(xAxis) > self.deadZone then
318
self._thisFrame['left'] = true
320
self._thisFrame['right'] = true
324
if math.abs(yAxis) > self.deadZone then
326
self._thisFrame['up'] = true
328
self._thisFrame['down'] = true
333
Sprite.endFrame(self)
336
-- private method: _dispatchPress
337
-- receives a Love joystickpressed callback and hands it off
338
-- to the appropriate gamepad.
340
_dispatchPress = function (number, button)
341
if the.gamepads[number] then
342
the.gamepads[number]:buttonPressed(button)
346
-- private method: _dispatchRelease
347
-- receives a Love joystickreleased callback and hands it off
348
-- to the appropriate gamepad.
350
_dispatchRelease = function (number, button)
351
if the.gamepads[number] then
352
the.gamepads[number]:buttonReleased(button)