Jump to content

Phaser + CocoonJS (and possibly Aurora) Gamepad problems and questions


Recommended Posts

As you might have seen a few days ago, I've been trying to work out what is needed to get Phaser working as best as possible on an Ouya using CocoonJS. It has been a very frustrating road and, while I have had some successes, I've also finally hit a point where I really want some other people's opinions on where to go next.


First, though, some solutions.


So, as it turns out, I was only partially right in the additional property to test for in my change to the "pollStatus" code for gamepad input. It actually needs to test for the property and call the function too. Here is the code for that.

var rawGamepads = (navigator.webkitGetGamepads && navigator.webkitGetGamepads()) || navigator.webkitGamepads || (navigator.getGamepads && navigator.getGamepads());

(This has the added benefit of working in Firefox Aurora too now, but more on that a little later in this post.)


Through my testing, I was at first surprised and then highly annoyed to learn that the 'index' property of gamepads in CocoonJS is unreliable. While the specification states indices start at zero, it doesn't include how counting should happen between gamepads being connected, disconnected, or reconnected. The result of this is inconsistency is that, in CocoonJS anyway, you might get "0, 1, 2" for the first three controller indices, or you might get "0, 5, 8" sometimes. (It also doesn't help that the CocoonJS Custom Loader remembers the last index as long as it is running. I was up to an index of 25 at one point yesterday.)


To combat this issue, and hopefully not break the existing Phaser code for other systems, I have the following patch for "ongamepadconnect."

 this._ongamepadconnected = function(event) {            var newPad = event.gamepad;            _this._rawPads.push(newPad);            for (var i in _this._gamepads)            {                if (!_this._gamepads[i].connected)                {                  _this._gamepads[i].connect(newPad);                  break;                }            }        };

Instead of trusting the index of the gamepad, it looks for the first open slot within the four gamepads (as of 1.1.5 in Phaser) and 'connects' it. If all are connected, "_gamepads" is not updated.


And here is the patch for "ongamepaddisconnected" too.

this._ongamepaddisconnected = function(event) {            var removedPad = event.gamepad;            var removedPadIndex = 0;            for (var i in _this._rawPads)            {                if (_this._rawPads[i].index === removedPad.index)                {                  _this._rawPads.splice(i,1);                  removedPadIndex = i;                }            }            _this._gamepads[removedPadIndex].disconnect();        };

This time, instead of removing according to the "removePad.index" (as was previously the case), it finds the index of the pad to remove from "_rawPads" and uses that.





Because I wanted to test the above code on another system, I turned to running in Aurora (since I knew it supported the two events). This became a very Good News / Bad News situation.


Good News: Aurora passes the same "(navigator.getGamepads && navigator.getGamepads())" test CocoonJS does. No changes there. And there is now a new 'connected' property per gamepad built in too.


Bad News: Gamepads no longer have a 'timestamp' property and buttons are now "GamepadButton" objects. The former is a fairly easy fix. Test if the index of the button array is an object and then look for its 'value' (float) or 'pressed' (boolean) property.


The later is more complicated, and a problem I've recently learned CocoonJS suffers from too. (After the Aurora testing, I used the same code on my Ouya in CocoonJS. It has a 'timestamp' per gamepad, it turns out, but it remained a '0' during all of my testing. Not helpful. At all.)





All of this explanation and code now brings me to some questions:

  • Should the Phaser code be re-written to match these two systems? And if so, what is the best way to go about it?

It should be possible to use "this.game.time.now" to record our own timestamps. And I think this could even happen as part of "pollStatus" function somehow. But I really want some second, third, and maybe even fourth opinions about how to go about it, or if it should even be done in the first place.


After all, the Aurora and CocoonJS timestamp issues might work themselves out in their next versions. Or they may not. I don't know if it is worth waiting several weeks at a minimum to find out.

  • Is there anyone out there willing to either work with me or independently collaborate on this Phaser + CocoonJS debugging?

I'm making progress in fits and starts. And I know other people are waiting for the go-ahead to start using Phaser in CocoonJS without problems.


I figure there has to be at least one other developer willing to just check over that "Yes, this works for me too" or "Nope, I don't see that here" on these various changes. While I was thrilled @rich was willing to adopt my earlier changes, it has made me more skittish the deeper I go and the more little bits of code I change to get Phaser working in CocoonJS as smoothy as possible.

Link to comment
Share on other sites

Thanks, @rich.


Since posting that, I've been thinking it might be easier in the short term to make a Phaser plugin that handles gamepad input specifically for use under CocoonJS on the Ouya. Something that avoided these two issues, indices and timestamp, but acted like the current Phaser gamepad API.


It would also allow for a different set of button constants, threshold, and deadzone values too. All things, I know from previous experiences with the Ouya, that will be needed after the polling issue is worked out.

Link to comment
Share on other sites

@rich: I've been learning that's the case, yeah. There are people interested in doing HTML5 development using Phaser for the Ouya, but I haven't found another person specifically working on these problems and willing to spend hours digging through Phaser's code to solve them


@kenyee: Yeah. And most likely, yes. If there is someone who has an Android device and a compatible gamepad, we could probably get confirmation if CocoonJS acts the same way on other platforms. (From my research, this table, http://buy.thegameklip.com/pages/compatibility, seems to be pretty good for detailing which phones have plug-and-play support for PS3 controllers. However, maybe the device needs to be rooted too? I'm not sure.)


Anyway, as progress toward a solution to these latest hurtles, I've done the following two things:


  1. Submitted a question on the Ludei Help Center to get confirmation if these are known issues, the index and timestamp problems, and if they have already been fixed in the upcoming version of CocoonJS.
  2. Started work toward a fixed rate (150 ms) polling plugin for Phaser that will try to autodetect what type of controller (Ouya, Xbox 360 compatible, or PS3 compatible), load new deadzone values, and configure correct button mappings.

As progress is made, I'll update this thread to let other people know.

Link to comment
Share on other sites

Some progress:


I now have working code that takes into consideration the unreliable 'index' and 'timestamp' properties when using CocoonJS on the Ouya for gamepads using fixed rate polling. It has allowed me to individually test every button and axis value across Ouya, Xbox 360, and PS3 gamepads.


I consulted the newest edition (25 February 2014 as of this writing) of the W3C Gamepad specification and specifically the newer Remapping section and verified that CocoonJS-Ouya maps all gamepad types against the 'standard' button mapping layout, but with the following caveats:

  • Select/Back (button[8]) and Start/Forward (button[9]) are mapped to "Quit application" and "Ouya button." Pressing button[8] will trigger a prompt to end the application while under CocoonJS and double-pressing button[9] triggers the Ouya system overlay. (Note: the Ouya gamepad does not have these buttons itself.)
  • The d-pad (button[12], button[13], button[14], and button[15]) do not work on Xbox 360 compatible gamepads on the Ouya. (This is a known issue and is confirmed in the official Ouya Unity code too.)
  • Single-pressing the Ouya button (button[16]) or its equivalent on other gamepads does not produce a value. However, because double-pressing button[16] is a system-level interrupt, it will always bring up the Ouya system overlay.

Now for the bad news:


As I mentioned in this post, I have recently documented a bug where the first ([0]) gamepad will often produce out-of-range values for its axes[0] and axes[1] while at rest. Moving them at all produces the correct values, but the at-rest values are frequently quite wrong. (This picture and associated tweet is also visual proof of the ever-increasing index value problem too. It should not be possible to get an index of 10 unless there were that many gamepads paired with the system as well -- and there weren't.)


Future-proofing recommendations for Phaser:


The most recent Working Draft of the Gamepad specification also includes the GamepadButton interface and its associated 'value' (double) and 'pressed' (boolean) properties. I haven't checked if Phaser 1.2 tests for these yet, but it probably should. In all likelihood, Phaser 1.2 and the newest version of Firefox (which has this interface) will ship within a week of each other in March 2014.


(Aside: I have working code that uses the older "MozGamepadConnected" and "MozGamepadDisconnected" events. Phaser should probably support these two as well -- and have code in place to swap the different button layouts. As I know, for example, that the correct Xbox 360 axes are axes[0], axes[1] for left stick and axes[3], axes[4] for right stick in Firefox Aurora currently.)

Link to comment
Share on other sites

Introducing the Phaser CocoonJS-Ouya Gamepad plugin!


It is still in 'beta,' but seems to work well in the testing I've done and, most importantly, takes into account the few problems I am aware of with CocoonJS + Ouya gamepads.


The solution I came up with was to copy over the Phaser.Gamepad and Phaser.SinglePad code, rename the objects, and make changes in a few functions to match the research I've done. I also, as I'll see about adding to Phaser proper soon, wrote in a radial deadzone algorithm for detection of values normalized within axis deadzones. It gets rid of that input 'snapping' when an axis value suddenly isn't in the axis deadzone -- a smoother transition over that threshold.


I also extended the number of possible gamepads from 4 to 11. At least according to the official Unity SDK code, the Ouya can support up to 11 gamepads at once.

Link to comment
Share on other sites

  • 5 weeks later...

@ChuckLeone: I was going to write up the instructions today for getting CocoonJS 1.4.7 working on the Ouya as a blog post, but I just got the e-mail that version 2.0 is out. If you really want to use 1.4.7 (which has many problems with Phaser and especially with gamepads themselves), send me a direct message and I would be happy to reply back with the instructions.


Otherwise, if you don't mind waiting a few days, I'm going to need to test CocoonJS 2.0 now, see what it offers, and if the old problems still exist.

Link to comment
Share on other sites


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...