I recently posted about some newly discovered trouble with my game on device. You press a button rapidly to increment a score, but very rapid pressing (which is expected in a certain context; see video in thread) isn't upping the score as fast, and after trying every relevant approach from the docs and the forum, I'm betting it's the system's button debounce, based also on this explanation.
Assuming there's a path via software, I'm imagining a way for extra-rapid button presses to be recognized in fewer cycles; a call to set/request a smaller debounce window for edge cases like mine. Thanks love u bye
Based on @dave ’s description, the maximum rate is 50hz. Humans can only press buttons in the 10-20hz range so this should be fine (note that this is different than timing a single press to a single 60hz frame. )
However, what I guess is happening is that the fast tapping, while being relatively slow, is spending less time pressed than unpressed. Either it’s not being held long enough to register, or it’s unregistering before your update.
Still interested in a definitive answer here, if Dave or someone from the team could lend one. I'm small potatoes, but in some respects this is make-or-break for the intent of the game...!
If we change from the current state mask to an event list we'd be able to handle multiple presses per frame: Inconsistent d-pad button input order - #3 by dave I'll try that soon, let y'all know how it works out.
Okay, here's what I wound up doing.. I decided this new behavior should be opt-in so that it doesn't present any surprises to existing code, so in Lua I've added playdate.setButtonQueueSize() to tell the system how many button events in a single frame you want to be able to handle. The callbacks come the normal way, through the playdate.[left/right/up/down/A/B]Button[Up/Down]() callbacks, and there's a new bonus argument to those functions in this case: the timestamp when the button press/release was recorded.
This was a nice excuse to finally add button callbacks to the C API, so over there I added playdate->system->setButtonCallback(cb, userdata, queuesize), where the callback looks like int buttoncb(PDButtons button, int down, uint32_t when, void* userdata).
Let me know if you have any feedback or questions! I've scheduled this for 2.2 (needs to wait for a minor release since it's an API addition), and I have no idea when we'll have that out.
I'm going to have to call this unsolvable for now -- probably a hardware drawback unless C might improve it. I got 2.4.0 and used setButtonQueueSize() (under initialize()), but I'm afraid it didn't fix anything, no matter what I set the size to. Using it in my test script got the same result.
If someone sees this in the future and has an idea, you may message me here or email rbbipedal.dog. Thanks.
If setButtonQueueSize() isn't helping here, that's a bug--I added it specifically to address this problem. Here's the test program I used for the feature: buttonqueue.lua.zip (1.3 KB) It sets the refresh rate to 2 fps then counts how many button events it receives per frame on the d-pad and B button. Press A to turn the queue on and off.
Can you give this a try and see if it works as advertised?
OK, I tried the sample script, but maybe I'm just not sure what to look for. The queued events get up to 3 or 4, so I suppose it works, but I'm still wondering how to translate that to a score that is updating instantly. (I tried adding a similar score count from my test script, but it appeared unaffected.) It's still curious why rapidly alternating two buttons will update a value faster than a single button pressed at a similar rate.
I'm concluding this is a hardware problem. The design of the tactile switches of the Playdate's buttons just (apparently) won't allow a new press to be registered before the previous is finished (i.e. the switch goes back up). Gamepad buttons with conductive pads or the switches used in Nintendo systems (for instance) are better at taking ultra-rapid changes in presses, and I finally used Mirror to confirm this for myself.
Apologies for kind of going in circles on this till now, but Dave, thanks for your assistance and SDK work. This tiny game can just get too intense!
What does returning non-zero from the button callback do? The docs say "The function should return 0 on success or a non-zero value to signal an error." but not what signaling an error achieves. I tried it myself and it seems like it just calls it over and over again.