/ld27

To get this branch, use:
bzr branch /bzr/ld27
1 by Josh C
zoetrope 1.4
1
-- Class: Gamepad
35 by Josh C
cluke009 zoetrope + my spritebatch changes
2
-- This represents a single gamepad connected to the user's computer. This offers the
1 by Josh C
zoetrope 1.4
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>.
35 by Josh C
cluke009 zoetrope + my spritebatch changes
5
-- (Incidentally, a hat is used for things like a digital control pad.)
1 by Josh C
zoetrope 1.4
6
--
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.
10
--
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'.
16
--
17
-- Extends:
18
--		<Sprite>
19
20
Gamepad = Sprite:extend
21
{
22
	-- Property: number
23
	-- The index of the gamepad, starting at 1.
24
25
	-- Property: name
26
	-- The name of the gamepad, e.g. "XBox Controller".
27
28
	-- Property: numAxes
29
	-- The number of available axes, e.g. for analog controls.
30
31
	-- Property: numBalls
32
	-- The number of available balls.
33
34
	-- Property: numButtons
35
	-- The number of available buttons.
36
37
	-- Property: numHats
38
	-- The number of available hats, e.g. digital movement controls.
39
40
	-- Property: axes
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.
43
44
	-- Property: balls
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.
47
48
	-- Property: hats
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
51
52
	-- Property: deadZone
53
	-- Any motion by an analog control (from 0 to 1) less than this value is
54
	-- ignored when simulating digital controls.
55
56
	deadZone = 0.1,
57
58
	-- private property: _thisFrame
59
	-- what keys are pressed this frame
60
	-- if you are interested in this, use allPressed() instead
61
62
	_thisFrame = {},
63
64
	-- private property: _lastFrame
65
	-- what buttons were pressed last frame
66
67
	_lastFrame = {},
68
69
	new = function (self, obj)
70
		obj = self:extend(obj)
71
		assert(type(obj.number) == 'number', 'must set a gamepad number')
72
73
		obj.axes = {}
74
		obj.balls = {}
75
		obj.hats = {}
76
35 by Josh C
cluke009 zoetrope + my spritebatch changes
77
		if obj.number <= love.joystick.getJoystickCount() then
78
			-- if not love.joystick.isOpen(obj.number) then love.joystick.open(obj.number) end
79
			Joystick = love.joystick.getJoysticks()[obj.number]
80
			obj.name = Joystick:getName()
81
			obj.numAxes = Joystick:getAxisCount()
82
			obj.numButtons = Joystick:getButtonCount()
83
			obj.numHats = Joystick:getHatCount()
1 by Josh C
zoetrope 1.4
84
85
			-- set initial values for axes and balls
86
			-- hat values are strings so nil comparisons are safe
87
88
			for i = 1, obj.numAxes do
89
				obj.axes[i] = 0
90
			end
91
		else
92
			obj.name = 'NO DEVICE CONNECTED'
93
			obj.numAxes = 0
94
			obj.numButtons = 0
95
			obj.numHats = 0
96
		end
97
98
		love.joystickpressed = Gamepad._dispatchPress
99
		love.joystickreleased = Gamepad._dispatchRelease
100
		if obj.onNew then obj:onNew() end
101
		return obj
102
	end,
103
104
	-- Method: pressed
105
	-- Are *any* of the buttons passed held down this frame?
106
	--
107
	-- Arguments:
108
	--		button numbers passed as individual arguments
109
	--
110
	-- Returns:
111
	-- 		boolean
112
113
	pressed = function (self, ...)
114
		local buttons = {...}
115
116
		for _, value in pairs(buttons) do
117
			if self._thisFrame[value] then
118
				return true
119
			end
120
		end
35 by Josh C
cluke009 zoetrope + my spritebatch changes
121
1 by Josh C
zoetrope 1.4
122
		return false
123
	end,
124
125
	-- Method: justPressed
126
	-- Are *any* of the buttons passed pressed for the first time this frame?
127
	--
128
	-- Arguments:
129
	--		button numbers passed as individual arguments
130
	--
131
	-- Returns:
132
	-- 		boolean
133
134
	justPressed = function (self, ...)
135
		local buttons = {...}
136
137
		for _, value in pairs(buttons) do
138
			if self._thisFrame[value] and not self._lastFrame[value] then
139
				return true
140
			end
141
		end
35 by Josh C
cluke009 zoetrope + my spritebatch changes
142
1 by Josh C
zoetrope 1.4
143
		return false
144
	end,
145
146
	-- Method: released
147
	-- Are *all* of the buttons passed not held down this frame?
148
	--
149
	-- Arguments:
150
	--		button numbers passed as individual arguments
151
	--
152
	-- Returns:
153
	-- 		boolean
154
155
	released = function (self, ...)
156
		local buttons = {...}
35 by Josh C
cluke009 zoetrope + my spritebatch changes
157
1 by Josh C
zoetrope 1.4
158
		for _, value in pairs(buttons) do
159
			if self._thisFrame[value] then
160
				return false
161
			end
162
		end
35 by Josh C
cluke009 zoetrope + my spritebatch changes
163
1 by Josh C
zoetrope 1.4
164
		return true
165
	end,
166
167
	-- Method: justReleased
168
	-- Are *any* of the buttons passed released after being held last frame?
169
	--
170
	-- Arguments:
171
	--		button numbers passed as individual arguments
172
	--
173
	-- Returns:
174
	-- 		boolean
175
176
	justReleased = function (self, ...)
177
		local buttons = {...}
35 by Josh C
cluke009 zoetrope + my spritebatch changes
178
1 by Josh C
zoetrope 1.4
179
		for _, value in pairs(buttons) do
180
			if self._lastFrame[value] and not self._thisFrame[value] then
181
				return true
182
			end
183
		end
35 by Josh C
cluke009 zoetrope + my spritebatch changes
184
1 by Josh C
zoetrope 1.4
185
		return false
186
	end,
187
188
	-- Method: allPressed
189
	-- Returns all buttons currently pressed this frame.
190
	--
191
	-- Arguments:
192
	--		none
193
	--
194
	-- Returns:
195
	--		string button descriptions; if nothing is pressed, nil
196
197
	allPressed = function (self)
198
		local result = {}
199
200
		for key, value in pairs(self._thisFrame) do
201
			if value then table.insert(result, key) end
202
		end
35 by Josh C
cluke009 zoetrope + my spritebatch changes
203
1 by Josh C
zoetrope 1.4
204
		return unpack(result)
205
	end,
206
207
	-- Method: allJustPressed
208
	-- Returns all buttons just pressed this frame.
209
	--
210
	-- Arguments:
211
	--		none
212
	--
213
	-- Returns:
214
	--		string button descriptions; if nothing is just pressed, nil
215
216
	allJustPressed = function (self)
217
		local result = {}
218
219
		for key, value in pairs(self._thisFrame) do
220
			if value and not self._lastFrame[key] then table.insert(result, key) end
221
		end
35 by Josh C
cluke009 zoetrope + my spritebatch changes
222
1 by Josh C
zoetrope 1.4
223
		return unpack(result)
224
	end,
225
226
	-- Method: allJustReleased
227
	-- Returns all buttons just released this frame.
228
	--
229
	-- Arguments:
230
	--		none
231
	--
232
	-- Returns:
233
	--		string button descriptions; if nothing is just pressed, nil
234
235
	allJustReleased = function (self)
236
		local result = {}
237
238
		for key, value in pairs(self._thisFrame) do
239
			if not value and self._lastFrame[key] then table.insert(result, key) end
240
		end
35 by Josh C
cluke009 zoetrope + my spritebatch changes
241
1 by Josh C
zoetrope 1.4
242
		return unpack(result)
243
	end,
244
245
	buttonPressed = function (self, button)
246
		self._thisFrame[button] = true
247
	end,
248
249
	buttonReleased = function (self, button)
250
		self._thisFrame[button] = false
251
	end,
252
253
	endFrame = function (self, elapsed)
254
		-- move button values to the previous frame
255
256
		for key, value in pairs(self._thisFrame) do
257
			self._lastFrame[key] = value
258
		end
259
260
		-- set values
261
262
		for i = 1, self.numAxes do
35 by Josh C
cluke009 zoetrope + my spritebatch changes
263
			self.axes[i] = Joystick:getAxis(i)
1 by Josh C
zoetrope 1.4
264
		end
265
266
		for i = 1, self.numHats do
35 by Josh C
cluke009 zoetrope + my spritebatch changes
267
			self.hats[i] = Joystick:getHat(i)
1 by Josh C
zoetrope 1.4
268
		end
269
270
		-- simulate digital controls
271
272
		self._thisFrame['up'] = false
273
		self._thisFrame['down'] = false
274
		self._thisFrame['left'] = false
275
		self._thisFrame['right'] = false
276
277
		if self.numHats > 0 then
278
			local hat = self.hats[1]
279
280
			if hat == 'u' then
281
				self._thisFrame['up'] = true
282
			elseif hat == 'd' then
283
				self._thisFrame['down'] = true
284
			elseif hat == 'l' then
285
				self._thisFrame['left'] = true
286
			elseif hat == 'r' then
287
				self._thisFrame['right'] = true
288
			elseif hat == 'lu' then
289
				self._thisFrame['up'] = true
290
				self._thisFrame['left'] = true
291
			elseif hat == 'ru' then
292
				self._thisFrame['up'] = true
293
				self._thisFrame['right'] = true
294
			elseif hat == 'ld' then
295
				self._thisFrame['down'] = true
296
				self._thisFrame['left'] = true
297
			elseif hat == 'rd' then
298
				self._thisFrame['down'] = true
299
				self._thisFrame['right'] = true
300
			end
301
		end
302
303
		if self.numAxes > 1 then
304
			local xAxis = self.axes[1]
305
			local yAxis = self.axes[2]
306
307
			if math.abs(xAxis) > self.deadZone then
308
				if xAxis < 0 then
309
					self._thisFrame['left'] = true
310
				else
311
					self._thisFrame['right'] = true
312
				end
313
			end
314
315
			if math.abs(yAxis) > self.deadZone then
316
				if yAxis < 0 then
317
					self._thisFrame['up'] = true
318
				else
319
					self._thisFrame['down'] = true
320
				end
321
			end
322
		end
35 by Josh C
cluke009 zoetrope + my spritebatch changes
323
1 by Josh C
zoetrope 1.4
324
		Sprite.endFrame(self)
325
	end,
326
327
	-- private method: _dispatchPress
328
	-- receives a Love joystickpressed callback and hands it off
329
	-- to the appropriate gamepad.
330
331
	_dispatchPress = function (number, button)
332
		if the.gamepads[number] then
333
			the.gamepads[number]:buttonPressed(button)
334
		end
335
	end,
336
337
	-- private method: _dispatchRelease
338
	-- receives a Love joystickreleased callback and hands it off
339
	-- to the appropriate gamepad.
340
341
	_dispatchRelease = function (number, button)
342
		if the.gamepads[number] then
343
			the.gamepads[number]:buttonReleased(button)
344
		end
345
	end
346
}