EDIT: Feel free to skip ahead to my third comment, and come back to the first two for context only as needed.
I asked this in a related thread, but it seems worthwhile calling out separately since it's pretty fundamental. The docs for
playdate.wait (which I assume also apply to
playdate.stop) say this (emphasis added):
Animation during this wait period is possible, but you will need to explicitly call
playdate.display.flush() once per frame.
I see from the docs that any
animators still run in the background, but I don't see how one would call
flush every frame, since there seems to be no per-frame callback while waiting/stopped.
update won't be called, by definition, and timers won't fire either, so as far as I can tell there's no opportunity to even call
flush as would be required to update the display apart from interrupts like button/key presses.
My goal is to effectively "pause" the underlying game while showing a menu, which itself includes some animations. Any help would be much appreciated!
(It would be awesome if there was some sort of pause stack, akin to the input handler stack, which enabled any new timers, sprites, etc. created after pushing to it to run normally while the ones on the level below all paused, and which removed and cleaned them up when popping, but that sounds like a pretty complex system…)
I’ve been pondering this further. I’m still quite curious to know whether there’s any way to hook into the game loop while waiting/stopped apart from interrupts, but perhaps that’s the wrong way to think about it.
If I understand the docs correctly, all
stop do is suspend calls to
playdate.update. Initially I’d assumed that it would function more like the system menu button which also stops clocks, but it doesn’t look like it. If all it does is avoid calls to
update, it would be just as easy to temporarily swap out the
update function for one which manages the paused state, during which one could still perform drawing and animation. I’d love to be able to mimic the effect of stopping timers entirely, but alas I can’t see how given that it’s not possible to set the
currentTime on a timer.
In other words, swapping out the update function get one as close as calling
playdate.stop to effectively pausing the game, and still enables animation above the paused game, but doesn’t offer any answer for ensuring timers are properly paused. Does anyone have any suggestions for how to effectively pause timers globally akin to the system menu button?
I think I can reduce this thread to a single question that would give me confidence in my approach:
Q: What does
playdate.stop actually do?
Specifically, does it do anything more than cease calls to
playdate.update? I'm still interested in the corollary, regarding whether there's any facility available for "truly" pausing timers as well, in the same way the system menu button does, but an answer to the main question above would suffice for now. Thanks!
Sorry I haven't gotten back to you sooner, didn't know the answers off the top of my head so I moved on to other questions I could answer quicker. So, the idea behind
playdate.stop() was if your game doesn't need to be constantly updating--say, it displays the current state of the game and doesn't do anything until a button is pressed--it can call that to stop the update() callbacks and save some battery life. I added that very early in development (git says July of 2014!) and I'm not sure anyone's ever used it. Looks like there are a few instances of it in the Single File Examples folder but it's not really used for anything. Anyway,
playdate.stop() predates timers by a long while and since it never wound up getting used for anything it was never tested alongside them.
CoreLibs/timer.lua uses the
playdate.getCurrentTimeMilliseconds() as a time base and I don't think
playdate.stop() should stop that clock. It's reasonable that even if you're entirely button-driven you still might want to know how long the game has been running without having to use the date/time functions. Looking at the code, I think you can get this working like you expect if you pause the timer when you call
playdate.stop() and add this to the
playdate.timer:start() function in
timer._lastTime = playdate.getCurrentTimeMilliseconds()
We have a bug open on timers jumping ahead after unpausing but Dan's been busy. I'll submit this as a possible fix and we'll get it into a future release, but the nice thing about having the code in CoreLibs is you can fix it on your end now.
Ah, that’s all very useful context. Thanks for the background. It sounds like
stop just wasn’t designed for what I was attempting to use it for.
For additional context on my end, I’m trying to do something a little unconventional, which is to simulate the effect of pausing the game just like the system menu does. That breaks down into two sub cases, one of which your suggestion will work fine for, which is pausing my own game. The other use case is for a little visual debugging library I put together called Acetate, from which I’m attempting to essentially pause someone else’s game in response to a keyboard shortcut while showing a debug overlay.
So far I’m simulating this by:
- Saving off the current update function and swapping in a no-op of my own
Assuming sprite and timer updates are being done in the game’s
playdate.update handler, and the game also implements any necessary timer logic in their own pause/resume handlers, it should work.
Two last questions:
- Does the system menu in fact stop the
- Does the system menu do anything else besides that which I should be thinking about to simulate its behavior?
When the system menu closes it sets the current time to the time you opened it, so yeah it effectively pauses it. The only way I can think that detail would make a difference is if you have a custom menu item that calls
getCurrentTimeMilliseconds? Nope, looks like we're resetting the time before calling the menu callbacks.
The one other thing I can think of that opening the menu does, and it'll unfortunately be impossible for you to replicate, is pausing game audio. I'll file a feature request for that but I'm not sure how generally useful it is.
Got it, thanks. I won’t be able to replicate either of those behaviors. The audio aspect doesn’t actually matter that much since it’s just a tool for visual debugging, though it would sell the effect. It would be nice to achieve the full time paused effect, but I totally understand that my use case is quite niche and that allowing one to stop that clock is more likely risky than useful in a game context. Since it’s just a dev tool anyway, neither are a big deal.
I believe this does still have an impact because it also effectively pauses timers, given that their time basis isn’t advancing during that interval, without any effort on behalf of the game dev. Ideally I could achieve that effect as well, but I totally understand that it’s outside the bounds of what an app is expected to be able to do.