My questions were answered, (thank you again v much @Nic )
I just wanted to add this for posterity, in case someone comes poking through curious about image drawing vs sprite drawing (or maybe @matt will find interesting in their benchmarking work), in the kinds of scenarios I described above (lots of removals, or lots of movement on many sprites). I dug up a small little test which exercises the latter (movement). Raw numbers aren't particularly important (since nothing else is going on, e.g. its not in a real game), rather the scaling properties was the focus here.
Tested on device, on newest firmware.
- at 50 images ( sprites = 47fps, images=48fps),
- at 100 images ( sprites = 37fps, images=48fps), ~30% faster
- at 150 images ( sprites = 27fps, images=36fps), ~33% faster
- at 200 images ( sprites = 20fps, images=29fps), ~45% faster
- at 250 images ( sprites = 18fps, images=27fps), ~50% faster
image used:

import "CoreLibs/graphics"
import "CoreLibs/animation"
import "CoreLibs/sprites"
import "CoreLibs/timer"
import "CoreLibs/utilities/sampler"
gfx = playdate.graphics
snd = playdate.sound
dsp = playdate.display
gfx.setColor(gfx.kColorWhite)
dsp.setRefreshRate(0)
num_sprites = 250
images = {}
x_min = 10
x_max = 300
y_ = 30
x_ = 10
for i=1,num_sprites do
table.insert(images, {gfx.image.new("image-1.png"), x_, y_, 1})
x_ = x_+3
y_ = y_+1
end
sprites = {}
local image = gfx.image.new("image-1.png")
y_ = 30
x_ = 10
for i=1,num_sprites do
local sp = gfx.sprite.new(image)
sp:add()
sp:moveTo(x_, y_)
table.insert(sprites, sp)
x_ = x_+3
y_ = y_+1
sp.dir = 1
end
for i=1,num_sprites do
assert(images[i][4] == sprites[i].dir)
assert(images[i][3] == sprites[i].y)
assert(images[i][2] == sprites[i].x)
end
local use_sprites = true
function playdate:update()
gfx.clear()
if playdate.buttonJustPressed(playdate.kButtonA) then
use_sprites = not use_sprites
end
if use_sprites == true then
for i=1,#sprites do
local spr = sprites[i]
spr:moveTo(spr.x+10*spr.dir, spr.y)
if spr.x >= x_max then
spr.dir = -1
elseif spr.x <= x_min then
spr.dir = 1
end
end
gfx.setColor(gfx.kColorBlack)
--sample("drawing", function()
gfx.sprite.update()
--end)
gfx.setLineWidth(0.5)
gfx.drawLine(0, 220, 400, 220, 2.0)
gfx.drawText("sprite mode", 0, 0)
playdate.drawFPS(340, 225)
else
for i=1,#images do
local img = images[i]
img[2] = img[2]+10*img[4]
if img[2] >= x_max then
img[4] = -1
elseif img[2] <= x_min then
img[4] = 1
end
end
--sample("drawing", function()
for i=1,#images do
local img = images[i]
img[1]:draw(img[2], img[3])
end
--end)
gfx.setLineWidth(0.5)
gfx.drawLine(0, 220, 400, 220, 2.0)
gfx.drawText("image mode", 0, 0)
playdate.drawFPS(340, 225)
end
end