The SDK provides a convenience for drawing a background via playdate.graphics.sprite.setBackgroundDrawingCallback(drawCallback). However, there is no documented method for removing it once set. I can achieve the result I'm after by setting it to a no-op function (function() end) but that feels like a hack. Given that it's a callback, I expect to be able to just set it to nil, as most executors of optional callbacks will check for nil before attempting to call them. However, calling setBackgroundDrawingCallback(nil) results in a runtime crash.
I'm honestly not sure if this is a bug, a feature request, or just a misuse of the API on my part, so please let me know if this belongs under another topic. My use case is setting a background for various levels, but sometimes a background isn't needed and I'm looking for the recommended way to clear it.
This method is often misunderstood as being a little more magical than it really is; all it does is create and configure a new sprite, and assigns drawCallback to the new sprite's drawing callback. (it's defined in CoreLibs/sprite.lua, and actually the entire source is right in the documentation if you would like to see what it does (See: Inside Playdate).
The newly-created sprite is returned from the function, so to remove it you can call :remove():
local bgSprite = playdate.graphics.sprite.setBackgroundDrawingCallback(drawCallback)
...
bgSprite:remove()
That said, I think you're right that passing nil should remove a previously-set background drawing callback. Looking at this also made me realize that if this method is called more than once, you'll end up with multiple background sprites, which feels like a bug to me. I'll file an issue and get a fix ready for this stuff as soon as possible!
Thanks Dan, that's clarifying. And I apologize, I should have dug a little deeper to check my assumptions. In fact, I did go read the docs, and the main documentation (in bright white text) actually supported my assumption that this would just configure the inner draw loop for the background object. I then glossed over the implementation details section, which would have corrected my seemingly reinforced but ultimately incorrect understanding.
That said, the behavior does go somewhat against my expectations! I think naming plays a part in that, because the side effect of creating a new sprite instance is non-obvious. My mental model was that this would set, overwrite, and hopefully "unset" the background drawing routine for a singular, static background object. The only "magic" I assumed was that the background object would live outside of the standard sprite list, as a singular special-case object which you could update the drawing routine for at any time.
Even if the functionality still manifests as a regular sprite, updating the behavior to avoid creating multiple instances, and to support passing nil (either to remove it, or at least result in a no-op draw handler that appears like a cleared background) sounds like an improvement. Thanks again!
I agree that the naming of the method suggests the usage you were expecting, and that's how it should behave.
I think this will be the new implementation, if you want to replace the implementation in CoreLibs before it makes it into an SDK release:
function spritelib.setBackgroundDrawingCallback(drawCallback)
if drawCallback == nil then
if bgsprite ~= nil then
bgsprite:remove()
bgsprite = nil
end
return nil
end
if bgsprite == nil then
bgsprite = gfx.sprite.new()
bgsprite:setSize(playdate.display.getSize())
bgsprite:setCenter(0, 0)
bgsprite:moveTo(0, 0)
bgsprite:setZIndex(-32768)
bgsprite:setIgnoresDrawOffset(true)
bgsprite:setUpdatesEnabled(false)
bgsprite:add()
end
bgsprite.draw = function(s, x, y, w, h)
drawCallback(x, y, w, h)
end
return bgsprite
end