How to program your gamepad

2013-05-16

I've entertained the notion on and off as of late, but when I finally acquired a gamepad it was a spur-of-the-moment decision (and possibly a bad one if my finances don't improve). The tipping point was the double realization that supporting a gamepad is actually quite easy, yet relatively few Linux games bother, so I could add support in my own games -- learning how it works in the process -- and perhaps raise awareness of this issue with a platform that still struggles to gain acceptance among gamers.

There was also the fact that very little appears to be written about actually designing games to work with a gamepad versus mouse+keyboard, as if it was a simple matter. And that's really odd, considering how the control scheme is usually the biggest complaint about games ported from consoles to the PC.

Prior to now, the last time I used a gamepad it was soldered on to the NES clone I owned in the 1990s. In the mean while, a pair of analog sticks have become standard on all but the cheapest models, along with a plethora of buttons. Mine for example has 10, all neatly numbered (although it reports 12 to the driver). I wisely chose one where the vendor's website said "no driver required", which is laymanese for "works with the generic driver included with your operating system". Indeed, Linux recognized it instantly, and from there it was smooth sailing.

The next question was, of course, which platform to use. There is supposed to be experimental support in Firefox, but it's not enabled in the build I have. Luckily, there is no such problem with Pygame, the other main platform to which I ported my games. All you need to get started is documented here -- it really is that simple. (See the code below.)

As buttons are straightforward, the important thing I had to learn was that each analog stick is seen as a pair of axes, left-right and up-down, each going from -1 to +1 (or -32768 to 32767 in raw SDL), with zero being the neutral position. They're also usually expected to have some jitter, but mine just stay at zero if I take my thumbs off them; this is either a quality of the device or else a feature of the X11 joystick driver.

But how do I apply that to my games?

If you've played Square Shooter, you may have wondered about the control scheme that relies entirely on the left mouse button. That was intended to maximize portability (and indeed it turned out to map very well to touchscreens), but it was controversial and made the game quite hard. Which isn't a bad thing per se, as several players pointed out, but the difficulty always felt a bit artificial in this case.

The reason, obvious in retrospect, is that the game always wanted to be an omnidirectional shooter. And now it is! All I had to do was clone the functions that deal with input and change them to take relative coordinates instead of absolute:

	def thrust_at(self, x, y):
		if self.ship == None:
			return

		x -= self.ship.position.x;
		y -= self.ship.position.y;
		
		self.accel_x += x * 0.03;
		self.accel_y += y * 0.03;
		
	def thrust_by(self, x, y):
		if self.ship == None:
			return
		
		self.accel_x = x * 0.03
		self.accel_y = y * 0.03

The code to handle the gamepad itself is also no big deal:

	if pygame.joystick.get_count() > 0:
		joystick = pygame.joystick.Joystick(0)
		joystick.init()
		axes = joystick.get_numaxes()
	else:
		joystick = None
		axes = 0

	.
	.
	.
	
	running = True
	while running:

		.
		.
		.

		ev = pygame.event.poll()

		.
		.
		.

		if ev.type == pygame.JOYAXISMOTION:
			if axes > 1:
				accel_x = joystick.get_axis(0)
				accel_y = joystick.get_axis(1)
				model.thrust_by(accel_x, accel_y)
			if axes > 3:
				shoot_x = joystick.get_axis(2)
				shoot_y = joystick.get_axis(3)
				model.shoot_by(shoot_x, shoot_y)

But how did that change the gameplay?

For one thing, now you can shoot without moving the ship. And while aiming is harder, rapid fire more than compensates. As for flying the ship, I've been amazed at the precise control granted by the analog stick. The overall result is a game much closer to my original vision, and easier too. As a bonus, now I can finally play Square Shooter without fearing for the integrity of my mouse!

Importantly, all of this was achieved without touching the mouse code, so you can play the game either way. And while this won't always be possible, you should always at least consider adding gamepad support to your games.

Tags: , , .