I’m using SDL_GameControllerGetAxis to get the analog stick value, which works fine when I’m smoothly guiding the stick like normal (for example, when you’ve got your thumb on the stick and are using it to look around), but what I want to be able to do is quickly flick the analog stick in a direction, without having to keep your thumb on it. So when the player is holding the gamepad, they would have their right thumb over the action buttons by default, and then sometimes an event occurs where they must quickly respond to it by flicking the right stick in some direction, before returning their thumb to the action buttons.
The problem I’ve encountered is there are a handful of frames where the value returned by SDL_GameControllerGetAxis is in the opposite direction. Meaning, for example, if I flick the stick up, SDL_GameControllerGetAxis(controller_, SDL_CONTROLLER_AXIS_RIGHTY) will correctly return a value of -32768 for several frames, but after that it then returns a value of 19199 for several more frames which results in an incorrect and unexpected input event occurring, and then after that it settles on a value of -513, which is within the dead zone I have set. I don’t want to increase the dead zone to be large enough to include the value of 19199 because this causes some valid inputs to get dropped.
My theory about what’s happening here is that flicking the stick up is causing a very small and quick kickback that briefly pushes the stick down. If that’s correct, it seems like this would surely be a problem that other people have already encountered and come up with a solution for. Is there a standard way to handle this? Or, if that’s not correct, what might be going on here?
I agree with you on the source of the problem. The hardware itself usually dampens or mutes kick-back either mechanically or with a micro-timer, it’s strange to me that you are getting over 50% activation on a kickback. Do you have any other controllers to test against?
So there are at least three options, the initial one is to replace the controller, which probably is not an option. The others I’m aware of are:
Increase the dead-zone.
Apply a time-range in which you don’t register a parity-changed input.
Weighted input: Record the previous and current inputs, add them together and get an average result. A quick flick should still be caught, but a flick-back will have a negative added to a positive, the average will be closer to dead-zone and more likely to be ignored. You might need to increase the sample size to average based on how many kickback samples you are seeing.
I think #3 is the best option for the job. In this instance you will want to do more than 2 samples because the flick-back reading is so strong.
Thanks, I’ll give #3 a try and see how that works out! I was using an 8BitDo Pro2 bluetooth, and I swapped it out for my PS4 controller just to see, and it actually gets a similar but different result. What happens with the PS4 controller is it reverts back to the dead zone range, and then briefly bounces back up again to the valid range before going back to idle, so it results in a double input event.
I logged the exact analog y axis value for each frame and this is what it got for what should be one up flick of the stick:
I should recommend setting some kind of FPS limiter on the program, it looks like you are running at about 1000-3000 FPS or more.
I’ll walk back my statement about it likely being just a bad controller; I was able to get similar results by putting my FPS up about that high and flicking. If the gameloop runs at a more reasonable 60-240 FPS, I think you’ll find the chance of polling the controller during a kickback becomes more of a rare issue, however it still is a possibility.
Options 2 and 3 should be viable at 30 FPS or 5000 FPS. (Assuming you adjust the sample size of 3 as recommended above).
I would really like to hear someone else’s thoughts on this. Especially possible solutions I’m not aware of?
Oh, good call! You’re right, it’s running unrestricted in the range of 3700-3900 FPS. I tried adding a limiter and it broke some other stuff, so it actually looks like I’ve got a few issues to work out here.
I was able to work through the other problems that were exposed, and now it’s feeling pretty good. I tried limiting the FPS to 240, and I applied the input smoothing using a rolling average window size of 5 frames. I did notice it happened once, so you’re correct that it could still happen albeit much more rarely, though this may be within the acceptable error tolerance. I also tried setting the limit to 60 FPS and I noticed some input events were being missed, so I lowered the window size to 3, and that feels pretty good. I didn’t notice any issues when using those parameters, so I think that’s what I’m going to default to.