@stuffbyrae posted a great tutorial for running an “exit animation” after the user chooses Home from the System Menu (also plays when Stopping or Restarting the Simulator) using @NaOH’s discoveries in Swap Machina. Many thanks!
The Lua code there runs an imageTable from a PNG file. Here’s a variation that generates animation on the fly from code instead, including specifying FPS since setRefreshRate doesn’t apply:
function pd.gameWillTerminate()
--(DATA-SAVING CODE HERE IF NEEDED)
local exitFrames = 20;
local exitFPS = 30
local exitImages = gfx.imagetable.new(exitFrames)
local prepImage --Re-used to build each frame
--Preparation that SOME games will need, depending on whether they use setDrawOffset or unwanted draw modes:
gfx.setDrawOffset(0, 0)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
for f = 1, #exitImages do
prepImage = gfx.image.new(400,240, gfx.kColorBlack) --Must be new each loop, or all frames end up the same!
gfx.lockFocus(prepImage)
--DRAW GRAPHICS HERE
exitImages:setImage(f, prepImage)
end
gfx.unlockFocus()
local exitAnimator = gfx.animator.new((#exitImages / exitFPS) * 1000, 1, #exitImages) --Run through image table at the desired framerate
while not exitAnimator:ended() do
exitImages:drawImage(math.floor(exitAnimator:currentValue()), 0,0)
playdate.display.flush()
end
end
And I’m using the popular constants at the top:
local pd <const> = playdate
local gfx <const> = pd.graphics
Corrections/improvements welcomed.
Further tips:
• The Playdate holds on the last frame after the game exits, as the device reboots to Home/launcher. If you don’t want a frozen frame of motion, end on black or something.
• But sometimes I swear it holds on the second-to-last frame, or only partially re-draws the last frame (the top of it) during the reboot. So if that matters, consider adding one extra duplicate frame at the end of the table.
• There seems to be a VERY brief micro-flash of white screen before the rebooting process happens, even though after that the final game frame is held during that reboot delay. I have found no way to remove that brief white frame, but it’s barely noticeable even with a black screen.
• If you want something more complex than a single loop of “DRAW GRAPHICS HERE” code you can have multiple consecutive loops with different code, each adding frames to the image table.
P.S. FWIW—a memory tip that may not even matter:
Since my game is a RAM gobbler and I never wanted to risk a crash when generating that imageTable, on the off chance I was pushing the limit at the moment... along with saving progress I started my gameWillTerminate()
by setting a couple of large media variables (sound files in my case) to nil. Maybe that lets their memory get cleaned up in time? Maybe it does nothing of value? Doesn’t seem to hurt anything!