Mapping Analog Control Sticks on Xbox 360 Gamepad

ianfitz

  • Posts: 48
Hi All,

I have two XBox360 gamepads working on my Mac, with a game I made in Stencyl (yay!). So far, I've just been using the D-Pad and the A button. Pretty straightforward.

I'd now like to try out getting the analog control sticks, starting with the left one, working with Stencyl. A little trickier I'm afraid.

Does anyone understand how to correctly map an Xbox Controller's Analog Stick? An example project would be amazingly helpful.

Here's what I've puzzled out so far:

When I debug print using this method:



I got these results:

Down:
6, +axis 0,
6, +axis 1

Up:
6, -axis 1
6, -axis 0

Left:
6, +axis 1

Right:
6, +axis 1

Okay...so maybe the Analog Control Stick is just interpreted as one big, or maybe two buttons to stencyl...that makes sense, X axis and Y axis. And  maybe +axis 1 means "the stick has been moved in a positive degree using the Y Axis", and -axis 1 means "the stick has been moved in a NEGATIVE degree using the Y Axis".

But if that's the case, no clue why left and right print out both as +axis 1, and how I would differentiate that from the Y axis.

So then I thought, maybe what really matters is the level of pressure? At least it's something to debug print and see how it looks.

I did that like this:

Create a Key in Settings


Map the button to the key:


Print the pressure for the control:


The output I got was....

0

Just 0 over and and over again:



I'm stumped, anyone played with analog stick with Stencyl before, can give me some guidance here?

« Last Edit: February 10, 2015, 07:22:15 pm by ianfitz »

ianfitz

  • Posts: 48
FWIW, this isn't some academic pie-in-the-sky question.

Here's a youtube demo of Super Deference Fighter, a prototype I made in stencyl:

https://www.youtube.com/watch?v=xQWVM3w5Nfk

Right now the D-pad is controlling the direction of the laser/gaze (mashing A button controls bowing). I'd like to get the analog stick to control the laser, and possibly the bowing too.

Soooooo, that's my interest in this. Please help!


ianfitz

  • Posts: 48
Made a little bit of progress on this.

I mapped each direction of the left analog control stick like this (note also set the dead zone here as well):



And then set up a debug print like this:



And I got a reasonable response in the console. If I hit 'Up' on the left stick, I get '1', if I hit down I get '1', same for left and right. So, I seem to have everything mapped correctly now!

I think my problem now is that I am not getting any numbers BETWEEN 1 and 0, I am only getting "the stick has been pressed in  direction X" (1) or "the stick has not been pressed at all" (0).

Any idea how I can get the decimal values between 1 and 0, as that's the analog data I really need I think.

My guess is maybe I'm calling the print statement at the wrong time in the loop, so I will experiment with different times of doing that I guess (maybe in the draw loop I guess).

Edit: nope, sticking the debug print in my scene's 'when drawing' event didn't help, got same values of just 1 and 0.

ianfitz

  • Posts: 48
Okay, time for another sad, lonely, post where I talk to myself about how I can't get analog controls working!

Not much of progress report, other than I still haven't figured this out.

I'm still only getting '1' or '0' but no decimal value between the two when using analog control stick.

I thought maybe the problem was pegging the print statement against a key press event, as that's kind of a binary event.

So instead I just tried printing  control pressure during the 'Drawing' and the 'Updating' loops:





And I still get only output like this:



1's and 0's and not a decimal between'em.

I also thought, maybe the print statement is rounding my values for some reason? It doesn't seem like that would be a thing, but I tried 'Print as Absolute Value' and 'Print as Degrees' and didn't get any different output.

Can anyone help? Really hit a dead end here.

rob1221

  • *
  • Posts: 9473
The controller system hasn't received much testing due to very few Stencyl users making desktop games.  It's possible you aren't doing anything wrong and the system is just bugged or incomplete.

ianfitz

  • Posts: 48
Yea...that's what I'm kind of afraid of :(. Doing my best to document this if it is a bug so it gets resolved.

It really seems like the problem is the pressure value is being reported as an integer and not a float.

rob1221

  • *
  • Posts: 9473
Also make sure you're not testing in Flash.

twotimingpete

  • *
  • Posts: 1667
I'm not an expert at this. What I did was print the inputs for each button press on the 360 pad and determined how to map it that way.

My default map uses a 360 controller as a base. This is what that looks like.



I don't use any degrees of pressure sensitivity for different things (that may be cool in the next game though!) for now I just use off or on for each direction. For the record, I set analog sensitivity to 42%. otherwise it was so sensitive it was hard to get it centered.

ianfitz

  • Posts: 48
Also make sure you're not testing in Flash.

Bah, I wish that was it. If you look at the docs for gamepad support, you'll see one comment from me pointing out they need to make this clearer in the doc ;). So, I'm very aware of it and am running in Desktop mode, not Flash.

I don't use any degrees of pressure sensitivity for different things (that may be cool in the next game though!) for now I just use off or on for each direction. For the record, I set analog sensitivity to 42%. otherwise it was so sensitive it was hard to get it centered.

Thanks so much for checking out this thread!

Yea, I think I got as far as you did, our mappings look pretty similar.  And it works for me, but I am really trying to use the analog stick as an analog controller with degrees of pressure, otherwise it's basically a glorified D-pad. Nothing wrong with that, but not what I'm after.

That's good to know about 42% though, I've been using 25% as my reference point. At least when experimenting with how to extract pressure data, I'll leave it at 42% now.



ETHproductions

  • *
  • Posts: 430
I can report that this happens in Windows too, with my new Logitech F310 gamepad. I'm 99% certain it's a bug on Stencyl's side. I tried looking through the code, but I haven't figured anything out yet. I did notice that it detects the pressure correctly, because when the analog sensitivity is set to 1%, it detects much smaller of a joystick movement then when it's set to, say, 50%.

I think it would be a good idea to separate joysticks from buttons and triggers, if at all possible. Buttons can only be either up or down (0 or 1), and triggers have values in between (0 through 1), which can both be easily represented by the "get pressure for control" block. However, joysticks have multiple values, so it would be helpful if there were a block to get the x-distance, y-distance, normal distance or direction of a joystick.

Also, I noticed that when switching between X-input and normal input on my F310, it thinks that it's a new controller and thus increments the ID of the controller by 1. I don't know if this is a Stencyl problem, an OpenFL problem or a Windows problem, but I hope it's fixable as well.
Fontstruct - Stencyl - Website (in progress)

Proud Member of the League of Idiotic Stencylers; doing things in Stencyl that probably shouldn't be done.

ETHproductions

  • *
  • Posts: 430
OK, so I've done a bunch of testing, and I've found that commenting out this line in .../com/stencyl/Input.hx (in the function getButtonPressure):
Code: [Select]
case JoystickButton.AXIS:
if(_joyAxisState.get(b.a[0])[b.a[2]] == b.a[3]) // comment out this line
highestPressure = Math.max(highestPressure, Math.abs(_joyAxisPressure.get(b.a[0])[b.a[2]]));

seems to work, but only while the pressure is less than the analog sensitivity. So setting the analog sensitivity to 100% makes it work perfectly, but then any slight tilt of the joystick is detected. All in all, I think that without some serious reorganizing, this bug is not going to really be fixed. I may try tomorrow or Saturday to completely fix this.

Edit: Sorry, I should originally have given a bit more context about where that line was.

« Last Edit: June 19, 2015, 06:42:01 am by ETHproductions »
Fontstruct - Stencyl - Website (in progress)

Proud Member of the League of Idiotic Stencylers; doing things in Stencyl that probably shouldn't be done.

ETHproductions

  • *
  • Posts: 430
So I've just realized that the "get pressure for control" block only returns 0 or 1 intentionally; gamepad controls are meant to simulate keyboard controls, which can only be on or off. I think it would be much more fitting to turn it into a boolean block, but that already exists, in the form of "control is down". In other words, I think this block can be safely removed from the palette.

Today I'm going to copy the code from Input.hx into an extension, then take it from there. I hope to be able to separate the joysticks and triggers from buttons. I'm also going to modify the existing blocks to work with direct input (i.e. "0, -axis 0") as opposed to controls (i.e. "walk left"), although I will leave the existing control blocks in there, too.
Fontstruct - Stencyl - Website (in progress)

Proud Member of the League of Idiotic Stencylers; doing things in Stencyl that probably shouldn't be done.

ianfitz

  • Posts: 48
Hey sorry I didn't see your replies sooner.

Quote
So I've just realized that the "get pressure for control" block only returns 0 or 1 intentionally; gamepad controls are meant to simulate keyboard controls, which can only be on or off. I think it would be much more fitting to turn it into a boolean block, but that already exists, in the form of "control is down". In other words, I think this block can be safely removed from the palette.

Hmmm, maybe I'm missing something here. I agree that the d-pad should be 0 or 1, as it is an on or off state. However, this should not be true for the analog control stick. The whole point is that it has a range of values between 0 and 1, in floating point form. Imagine moving a character by creeping forward vs. an all out run. This is what the analog control sticks allow you to do.

If they can't do that, they are nothing more than a glorified d-pad, so what's the point?

So in my opinion the root issue is that the analog controls tick is not reporting a floating point value.

I have another thread for this in the paid user forums here:

http://community.stencyl.com/index.php/topic,40094.msg225615.html#msg225615

I did get some acknowledgement/response from Justin, but no progress on a fix yet.

Hope this helps.

Justin

  • *
  • Posts: 4716
Thanks for starting to take a look into this, ETH. The reported number for get pressure definitely isn't intentionally 0 or 1. It should be 1 if any dpad or button is pressed which maps to that control, otherwise a range from 0 to 1 for the highest pressure applied to any axis over its threshhold that maps to that control, or 0 if no buttons mapping to that control are pressed.

I've said this numerous times in the past, but today I'll honestly make myself take a look.
For Live Support: Join our discord server and ping me @justin.
I'm most often available between 10am and 10pm Japan time. (GMT+9)

ETHproductions

  • *
  • Posts: 430
OK, that makes more sense. I think I can fix this solely by modifying Input.hx, which I am doing right now.

Justin, I'm having trouble getting it running. First of all, here's the original code for the onJoyAxisMove function:
Code: [Select]
private static function onJoyAxisMove(e:JoystickEvent)
{
if(!_joyControllerReady[e.device])
initJoyController(e);

var oldState:Array<Int> = _joyAxisState.get(e.device);

var cur:Int;
var old:Int;

for(i in 0...e.axis.length)
{
if(e.axis[i] < -joySensitivity)
cur = -1;
else if(e.axis[i] > joySensitivity)
cur = 1;
else
cur = 0;

old = oldState[i];

if(cur != old)
{
if(old == -1)
joyRelease(e.device + ", -axis " + i);
else if(old == 1)
joyRelease(e.device + ", +axis " + i);
if(cur == -1)
joyPress(e.device + ", -axis " + i);
else if(cur == 1)
joyPress(e.device + ", +axis " + i);
}

oldState[i] = cur;
}

Now, I tried to change the reference of _joyAxisState to _joyAxisPressure, which contains arrays of Floats instead of Ints, but is not currently used anywhere else. Here's the updated code:
Code: [Select]
private static function onJoyAxisMove(e:JoystickEvent)
{
if(!_joyControllerReady[e.device])
initJoyController(e);

var oldState:Array<Float> = _joyAxisPressure.get(e.device);

var cur:Float;
var old:Float;

for(i in 0...e.axis.length)
{
if(e.axis[i] < -joySensitivity)
cur = e.axis[i];
else if(e.axis[i] > joySensitivity)
cur = e.axis[i];
else
cur = 0;

old = oldState[i];

if(cur != old)
{
if(old < -joySensitivity && -joySensitivity < cur)
joyRelease(e.device + ", -axis " + i);
else if(old > joySensitivity && joySensitivity > cur)
joyRelease(e.device + ", +axis " + i);
if(old < joySensitivity && joySensitivity < cur)
joyPress(e.device + ", -axis " + i);
else if(old > -joySensitivity && -joySensitivity > cur)
joyPress(e.device + ", +axis " + i);
}

oldState[i] = cur;
}

_joyAxisPressure.set(e.device, e.axis);
}

The problem is, as soon as I use any control on the gamepad, it freezes the game. However, if I change...
Code: [Select]
var oldState:Array<Float> = _joyAxisPressure.get(e.device);

...to this...
Code: [Select]
var oldState:Array<Float> = new Array<Float>();

...the game does not freeze, although it doesn't save the position of the axes anymore. Do you have any idea why it freezes?
Fontstruct - Stencyl - Website (in progress)

Proud Member of the League of Idiotic Stencylers; doing things in Stencyl that probably shouldn't be done.