Tutorial: Game controllers and axes

Tutorial: Game controllers and axes

In the previous tutorial about HID controllers, we showed you how to read button inputs from controllers. Generally speaking, controller buttons generate a simple “down” or “up” value, so you can easily determine if the player is interacting with that button.

About analog controls

In contrast, analog controls are more complex. These measure an almost infinite number of potential values that must be converted from their analog “infinity” to discrete digital values. In the case of the Corona, these values typically range from -1.0 to 1.0 and a very precise set of values anywhere between. To compound the complexity, some controls have two associated values — for example, an analog stick can be moved up and down in either direction over a varying distance, as well as left and right. Other controls like “triggers” generate values between 0.0 to 1.0 where the value increases the more you squeeze the trigger. As a broad definition, we refer to these control values as axis. For instance, the left analog stick has both an X axis and a Y axis. The right trigger, in comparison, has just a single axis to measure.

At the hardware level, analog sticks typically depend on springs to push the stick back to the neutral center position. However, these springs don’t always push the stick back to its perfect 0 value. In fact, a stick can be “noisy” and generate events even when the control isn’t being touched. Internally, Corona tries and minimize this noise, but because controllers vary considerably (even those from the same manufacturer), you should account for a certain amount of “slop” in your analog stick handling.

Another issue to contend with is the varied axis numbers that manufacturers assign to their controllers. For instance, the right trigger on the OUYA controller is axis number 6, but on a DualShock controller, that same control is axis number 14. In general, there are two ways to handle this:

  1. Build a mapping screen like those in many PC games, giving the player a chance to press the various buttons and controls, then gather those values and assign an axis number to each specific control. This is probably the best way to handle devices if you expect that players may use controllers that you know little about.
  2. Build a mapping system of specific controllers that you want to support. Since you’ll know in advance what each controller’s axes map to, you can build a table of inputs. Of course, you’ll still need to determine what the values are when you test a new controller.

Mapping system

For this tutorial, we’ll explore a basic mapping system of “known” controllers. To keep this tutorial relatively simple, we’ll only include two controllers, but you could repeat this basic pattern to handle additional controllers. Let’s look at some basic code:
[gist id=63eec6de3cb51635844c]
The first block of code creates a table based on the controllers we want to to support: the standard OUYA controller and the DualShock controller. The second table maps the physical control names to specific numbers. Later, we’ll execute code that reveals the real values that should be entered into this table.

Basic game setup

Let’s explore a simple game featuring two players that can be manipulated with a controller:
[gist id=5338269f243e8a8ffc40]
Each player is a colored square — one green and one red — and they begin in the center of the screen. We’ve added some properties to each player that represent the movement along the X and Y axes. The left stick is used to move the player and the right stick is used to rotate the player. Just for fun, we’ll use the triggers to change the color of the player. Because our axis events are not continuous, we need to use an "enterFrame" listener to move our player while the stick is being held (this listener will manage the player rotation as well).

The next step is a function that calculates the player rotation angle based on the X and Y of where the stick is being held. Note that you get one event for X movement and one event for Y movement. As a result, you must store the last value generated for X so that when you receive a Y event, you can compare the two. Likewise, if you get an X event, you must have access to the previous saved Y event.
[gist id=94edfa802eba7b88d902]

Game loop

Now let’s examine the game loop required to monitor the controller input:
[gist id=3623601816a1a31436d1]

Axis movement

Movement with the X and Y values is straightforward. If you simply want to move around, you can apply the values from the two axis events. At this point, you could apply physics impulses or movement, or in this case, simply apply the values from the controller. Rotation is more tricky — depending on what the rotation should do, you may have to convert the X and Y into an angle. You can also consider using the distance the stick is pressed to determine how fast to rotate. Since the X and Y values for rotation comes from two separate events, you need to store the two values and perform your movement based on those values.

Let’s look at the actual code to manage the axis data:
[gist id=409c3c16bcc65767e30a]

Initialize the controllers

Finally we need to initialize everything, including mapping the controllers:
[gist id=8f66d2f5887ff80bcd16]
The above code loops over the list of axes returned by the inputDevices[deviceIndex]:getAxes() function. It’s very likely that we don’t need all of the axes returned. This is where we use the two data tables at the top of this tutorial to pick an axis that we find and store the axis number into the second table.

Caution

Note that game controllers may run out of battery power and just “drop out” without warning. It’s also possible that a player may want to change controllers in the middle of the game, and thus “Joystick 2” is actually player 1. It’s your responsibility to manage these events, using the inputDeviceStatus event:
[gist id=762e46403020c34497d2]

In summary

This tutorial should get you up to speed on the axis type inputs on your controller and the basic mapping system.


Rob Miracle
rob@coronalabs.com

Rob Miracle creates mobile apps for his own enjoyment and the amusement of others. He serves the Corona Community in the forums, on the blog, and at local events.

4 Comments
  • Anton
    Posted at 03:52h, 25 September

    When will add support for keyboard control for mac simulator? Now it is very inconvenient to develop an application for android, ouya.

    Back in iOS 7 appeared maintain joysticks, whether you plan to add support?

    • Rob Miracle
      Posted at 16:24h, 25 September

      Engineering is looking into when they can schedule it in. Our focus was to get support out for the OUYA and those features were not available in iOS at the time.

      • Rob Miracle
        Posted at 16:26h, 28 September

        Just an update, some key and mouse support went into a recent daily build for the Mac sim (not iOS), but this is just the computer’s keyboard.

        • Ernest Szoka
          Posted at 12:40h, 28 January

          Mouse and Keyboard support doesn’t work on PC sim for iOS devices, but does for Android!