Gamepad events analysis

This post has 2 parts. The first is a step by step chronology of what I did. The second is an analysis, thoughts and questions.

Part 1:

I wanted to test every gamepad events to be sure I understand them all. The gamepad I used is a 3 days old brand new wired Afterglow, which is an Xbox 360 clone.

I started by using the 30 available gamepad events so every one of them fire a “Print String” node that write the name of the event on the screen when I press its corresponding button.

Here is how it looks like.

&stc=1

As I said, I did these tests to learn how the gamepad events work. So the first thing I learned is that all the events that return an “Axis Value” (I will call them the analog events for the rest of the post) always fire, even when their corresponding buttons are not touched on the gamepad. The result is that my code was a bit useless since every time I pressed a button, its text was immediately flushed away by the text from the always firing analog events.

I noticed that all the analog events have their digital counterparts as seen on this picture.

&stc=1

To fix my problem, I used “Gate” nodes, where the digital events open and close the gates for the analog events. Here is an example:

&stc=1

I also changed the text color (not shown on the picture) associated with the analog events so it’s easier to differentiate the digital and analog events. The output log (Window / Output Log) was also helpful.

The first button I tried was the Left Trigger. The logic of the code worked perfectly, no more useless wall of text on screen. I pressed very slowly to catch the first value it would write on screen when the digital event opens the gate for the analog event. To avoid that the value gets flushed away (because now that the button is pressed, it writes the value every frame), I just had to release the button. That first value was 0.121569.

I felt like it was wrong. The analog event nodes return values ranging from 0 to 1 (or 0 to -1). 0.121569 is 12% of the maximum value, and I got it as the very first value. It seemed to me that I was losing precision on the lowest values. So I investigated further.

I wanted to see what was the very first value the analog event could give me, but to do so I couldn’t use its digital counterpart anymore to control the gate since the problem might be that the digital event fires too late (thus it would open the gate much later than the analog event gives its first non-zero value).

So I used a random button (“Gamepad Face Button Left” event) to control the gate. That way, I got a wall of text only while that button was pressed. So I pressed it, having a wall of text saying “0.0”, again very slowly moved the Left Trigger until I saw the first none “0.0” value and then released the “Gamepad Face Button Left”. That first value was 0.007843.

That made much more sense to me. But I needed to push my knowledge further, so I tested every of the 6 analog events to know both their very first value (using a random button to control the gate) and the value at which their digital counterpart fires (using the said counterpart to control the gate).

Here are the values I got.

[TABLE=“class: grid, width: 500”]

Smallest (none zero) possible value
Digital counterpart fires at value

Left Trigger event
0.007843
0.121569

Right Trigger event
0.007843

0.121569

[TABLE=“class: grid, width: 500”]

Smallest (none zero) possible value

Digital counterpart fires at value

Moving Right

Moving Left

Moving Right

Moving Left

Left X event

0.002777

-0.001506

0.0[SUP]1[/SUP]

0.0[SUP]2[/SUP]

Right X event

0.002085

-0.001506

0.021821

-0.021281

[TABLE=“class: grid, width: 500”]

Smallest (none zero) possible value

Digital counterpart fires at value

Moving Up

Moving Down

Moving Up

Moving Down

Left Y event

0.001475

-0.001383

0.0[SUP]1[/SUP]

0.0[SUP]1[/SUP]

Right Y event

-0.002208

0.001424

-0.022797

0.021118

I used values with all the float precision to fill the tables because they are the exact numbers I got on every tries. I was actually surprised to observe such repeatable precision, but I was also happy with it because I like things that are predictable.

[SUP]1 [/SUP]The first none zero value came very closely after the digital event fired.
[SUP]2 [/SUP]After the digital event fired, there was still a little bit of space before the analog event reached its first none zero value.

Part 2:

Analyzing the tables:

  • The left and right triggers both react exactly the same, and fire their digital events at 12%.
  • The Left analog stick fires its 4 digital events before its 2 analog events return their first none zero value.
  • The Right analog stick does the opposite.
  • In both cases the digital and analog events fire close enough to each other.

My thoughts:
The digital events from the 2 sticks might fire close enough to their analog events, but I would still be expecting that they all start at the same %, or exactly at the very first none zero value. This should also apply to the trigger events.

Question:
Is there any reason why the 2 trigger buttons digital events react at 12% and not close to 0% like the other analog buttons?

Note that I didn’t do any test with the Release pins to see where they fire.

This is my first post, I hope I set it up all right.
I’m not English, sorry if I do not always sound right.

One thing to note is that the behaviors may be slightly different from platform to platform as the values you are referencing are provided by the OS input API in most cases. I’m going to assume you did this on windows and so we are talking about XInput.

The defines for the thresholds come from xinput.h.


//
// Gamepad thresholds
//
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD    30

We use the thresholds to determine when the synthesized button press has occurred. As you can see, the left and right thumb stick have different dead zones for reasons I’m sure you can find on the internet if you search hard enough but I don’t know.

For the axis value itself, we have a configurable deadzone value within the PlayerInput system (these properties can be seen in the Input section of Project Settings). This means that 0 is treated as the point you reach the deadzone threshold and then we scale the 0:1 (or -1) value that is passed to the event over the range DeadZone:1 (or negative as appropriate).

In future if you were doing similar testing I’d recommend using a branch testing that the value is != 0 instead of the gate behavior for removing the per-frame axis spam.

Can the stick & trigger ‘Dead Zones’ be exposed within the project settings, along with the ‘Invert Y Axis’ and a ‘Southpaw’ stick switch option please?

There are many of us that aren’t Coders, just using Blueprint, that will want to either tinker with these or leave these options open to players as part of the controller setup.

The axis properties are already exposed in the project settings in the input section as an advanced setting under binding. This exposes both dead zones and the invert properties for axes. An in-game invert y stick or southpaw options are game specific functionality that would need to be implemented through UI. That may not currently be possible through blueprints, but we will likely eventually be able to do so though it isn’t in the near term roadmap.

This is going slightly off topic but it’s the first time someone from Epic has comment on the Southpaw / Y Invert problems.

It is possible to set them up but there is an issue with the ‘Invert Y Axis’ option.It’s currently hard coded to the right stick and can be set in one of the ini files. It’s not possible to set / clear that flag as part of the Editor UI, meaning you’re stuck with it unless you go into the .ini files, which UE4 is trying to work around; it’s not possible to get / set the flag in Blueprints; it’s always bound to the right stick on joypads so it interfers with any control system you make on them that isn’t camera related, such as switching the sticks around for a Southpaw option. You have to do alot of work arounds in Blueprints to accomodate this.

Secondly, as a left handed games player, I know Southpaw controls are something that are frequently overlooked by Developers and supporting from it out of the box at the engine level garuntees that option for everyone. Epic added Southpaw support to their titles on a case by case basis but it was not included in the UE3 engine and the result was that most UE3 powered shooters didn’t include a Southpaw controller option, which is simple to add and opens games up to larger audiences.

Could the ability to turn on / off ‘Invert Y Axis’ and ‘Southpaw’ options not be added to the default settings, along with options to disable them if they’re not required for the game, & users be allowed to get / set them in Blueprints? The Southpaw option would need be capable of swapping the Invert Y Axis and Deadzone numbers too, which is what led me here in the first place.