Problem : Sprite still shows in the list when I do a #count on an array even after I do a :remove()
Description : I have an array call rocks. I initialize it empty at first with rocks = {}. Then add some sprites to it. Later I cycle through them and remove them by doing rock[i]:remove(). It removes from the screen just fine, but when I do #rocks to get a count it still has the same amount...
I was expecting the table count to go down as I remove them. What am I missing?
Here is a little demo to showcase what I'm talking about.
main.lua
import "coreLibs/object"
import "coreLibs/graphics"
import "coreLibs/sprites"
import "coreLibs/timer"
import "Rock"--my rock class
local pd <const> = playdate
local gfx <const> = pd.graphics
local rocks = {}
function addRocks(amount)
local buffer = 16
local locx = 164
local locy = 140
if amount > 0 then
for i = 0 , amount do
rocks[i] = Rock(locx,locy)
rocks[i]:add()
if locx > 383 then
locx = 164
locy+=16
else
locx += buffer
end
end
end
end
local function initalize()
addRocks(105) -- Adding 105 rocks here
end
initalize()
function playdate.update()
if pd.buttonIsPressed(pd.kButtonA) then
print("rocks",#rocks)-- prints count from rocks
for i = 0 , #rocks do -- removes all rocks from screen
rocks[i]:remove()
end
end
gfx.sprite.update()
pd.timer.updateTimers()
end
Shows all rocks
Pressed A to remove all rocks. Console still shows a count of 105 O.....o
I pressed the button a lot to really show the count not changing.
fosterdouglas
(Foster Douglas / Everyday Lemonade)
#2
As far as I understand it, :remove() is removing the Sprite from the display list. In your playdate.update() function, you are doing this, but you aren't also changing the table that you initially added those rock Sprites to. If you want to manage that rocks table, probably you could call a table.remove(rocks, i) in that for loop.
The code rock[i]:remove() removes a rock sprite from the display list (the sprite system's internal list of active sprites). It doesn't remove the sprite from your own rock table. Perhaps the method should have been called removeFromDisplayList() for clarity.
if you want to clear your own rock list, you can just assign an empty table (rock = {}). To remove a single rock, you can do either
rock[i] = nil
or
table.remove(rock, i)
(Avoid doing the removal inside the for loop, though. Modifying a list while you're looping over it is a good way to get into trouble.)
I took a different approch! After looking through some similar topics I found an comment from sgeos
I was like O.......O Why didn't I think of that!
So now instead of removing from the list then adding I'm just adding all the sprites up front. It's kind of a waste since not all sprites will be shown at once.
But if figure I get the performance boost by not having to generate new sprites and I don't have to :remove them from screen AND remove them from the array then add them back later so it's a win win in my book.
Here are my results
import "coreLibs/object"
import "coreLibs/graphics"
import "coreLibs/sprites"
import "coreLibs/timer"
import "Rock"
local pd <const> = playdate
local gfx <const> = pd.graphics
local rocks = {}
function addRocks(amount)
local buffer = 16
local locx = 164--164
local locy = 140
if amount > 0 then
for i = 0 , amount do
rocks[i] = Rock(locx,locy)
if i == amount then
rocks[i].isLast = true
end
rocks[i]:add()
if locx > 383 then
locx = 164
locy+=16
else
locx += buffer
end
end
end
end
--local x, y
function getLastPosition()
local x , y = 0,0
for i = 0, #rocks do
if rocks[i].isLast == true then
x , y = rocks[i]:getPosition()
if x >= 383 then
x = 164
y += 16
else
x += 16
end
rocks[i].isLast = false
break
end
end
return x, y
end
local function initalize()
addRocks(250)
end
initalize()
function playdate.update()
for i = 0 , #rocks do
rocks[i]:moveUp()
end
for i = 0 , #rocks do
if rocks[i].isCrushed == true then
local x, y = getLastPosition()
rocks[i].isCrushed = false
rocks[i].isLast = true
rocks[i]:moveTo(x,y)
rocks[i]:add()
end
end
gfx.sprite.update()
pd.timer.updateTimers()
end