How to remove from a table

,

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
image

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.
image

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.

Editing to not encourage bad programming habits. :slight_smile:

1 Like

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.)

3 Likes

Right, don't remove from within the loop ^....^

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



Scroll2