Hi! I'm new to game development and am trying to prototype a simple falling-note rhythm game for the playdate. I don't have a device yet and am testing using the emulator (1.9.0) on macOS 12.2.1 (Monterey).
An issue I'm running into is detecting input timings with ~ms precision. I'd like to have that level of input precision so I can set some strict timing windows, ideally allowing ~15-17ms of error for the tightest one. Unfortunately, all of my tests so far for capturing precise input timings seem to be limited by framerate:
- At the max fps of 50,
playdate.update
is called every 20ms, meaning detecting an input viaplaydate.buttonJustPressed
within that callback can be off by up to that amount. - When I register a custom input handler or define the default callback methods like
playdate.AButtonDown
and record the time the callback is called relative toplaydate.update
usinggetCurrentTimeMilliseconds
, the offset between the two is generally ~0-1ms. If I usegetElapsedTime
, the two values are identical. That suggests to me that the callbacks are run on the same loop as the update callback, but slightly beforeupdate
itself is called. It also suggests to me thatgetElapsedTime
is cached per loop, which is a bit surprising. - I looked briefly at the C API but haven't set up my dev environment to use it. It looks like it might be possible by listening for
kEventKeyPressed
events, but I'm hoping to avoid using C if possible.
My questions are:
- I'm not sure what the button input polling rate is; is it high enough that I can get reliable inputs at the ms level, or will I need to work around precision issues at that level too?
- Is there a way to access input timings more precisely through the Lua API? My testing suggests that all APIs are scheduled with frame updates, but it's possible that I'm misunderstanding my test results or that the emulator has different behavior than a physical device, which I can't yet test on.
- If not possible in Lua, will the C API provide more precise timings?
Edit: Here's the code I'm testing with, if that helps:
AButtonDownAt = nil
playdate.display.setRefreshRate(50)
function playdate.update()
if AButtonDownAt then
print("a button press detected " .. playdate.getElapsedTime())
AButtonDownAt = nil
end
end
playdate.inputHandlers.push {
AButtonDown = function()
AButtonDownAt = playdate.getElapsedTime()
print("inputHandlerFired " .. AButtonDownAt)
end,
}
Thanks, folks!