Weekly Update #7 Technical: Gamepad

Hello there!

since both of us are packed with tons of work, we want to use this Weekly to make a technical post about how we use the Gamepad API and why it’s so awesome.

Gamepad API

First, this post will only talk about us using the API in Chrome. Currently only Chrome supports the API in stable releases. Firefox offers it via special builds and Safari, IE and Opera still need to implement it.
On how to get started with the Gamepad API check out the great article from HTML5Rocks here: Link

 

The Gamepad API basically makes it possible to access gamepads in your browser. With this said the API itself is super small. You access all currently connected pads via a simple call to a webkit function!

Getting Started

So we started by pulling the array which contains all the gamepads:

 

var pads = navigator.webkitGetGamepads();

Every connected pad is a plain old object that looks like this:

id: "Xbox 360 Controller" // description of the gamepad
index: 0 // the index in the array
timestamp: 134862 // the time of the last update of the pad 
buttons: Array[16] // current states of all button.
    0: 0
    1: 1
    2: 0.45024
    3:
    ...
axes: Array[4]
    0: -0.94532432
    1: 0.01961
    2: -0.01721
    3: 0.33333

The button values we obtain are always in the range of [0 – 1]. The values will always be updated but as you can see there is no information about a press or release state. We needed to implement them on our own.

To check if a key was pressed or released we used the current state of a button and the state from the previous frame (the old state).
This roughly looks like this (not the exact code we use):

for (var i = 0; i < gamepads.length; i++) {
    var pad = gamepads[i];
    for (var j = 0; j < pad.buttons.length; j++) {
        var newState = pad.buttons[j];
        var oldState = this.getOldState(i, j);
        if (newState > 0) {
            if (oldState == 0) {
                // with have a key press
            }
        } else if (oldState > 0) {
            // we have a key release
        }
        this.setOldState(newState, i,j);
    }
}

With this code we can simply ask if a key was pressed by saving the key press in an array and then requesting it when we need it.

The Problem with the Deadzones

After we got the pulling done we integrated the gamepad system into CrossCode. At this point we were confronted with the problem of the DEADZONES! Aiming with the gamepad happens via the right stick. So when you hold the stick in a direction it will move the crosshair around. This is all good and worked nice until we noticed that when aiming up/down or left/right and then moving the stick just a tiny bit, the crosshair wouldn’t move.
So it seems as if some gamepads have a small deadzone integrated directly into the hardware where they will report a zero value rather then the expected value.
Here is a screen that illustrates this problem:
deadzone
The blue areas show the deazones where the input values stays at zero. Three approaches to tackle this:

 

  • Try other gamepads to check if this is a just hardware issue (which makes it a donotfix)
  • Map values from [deadzone,1] to [0,1] and [-1, -deadzone] to [-1,0], which allows the player to aim in any direction, just not continuously
  • Ignore the issue. The player can still move the avatar to adjust the aim in detail.

So aiming with the pad is a little bit harder (Nothing beats the mouse at precision!). But there is a good way to work around this. Because we use the left stick for moving you can move around in a 360° angle. This showed to be a good trade off and we even mastered the final challenge with a gamepad (You can test it your self in the upcoming TechDemo++).

Conclusion

All in all integrating the Gamepad API was fairly easy. There are some small issues and tweaks that needed to be done but we think we got it working pretty nicely.

 

2 Comments

Post a Comment

Your email is kept private. Required fields are marked *