# Code problem involving tables

Here’s a snippet of my code that isolates the problem. Issue is, when two or more circles are added to the table, when one is destroyed (table.remove) the project spits out an error. Any help is appreciated, thanks!

``````
--# Main

function setup()
displayMode(FULLSCREEN)
st = SmokeTest()
end

function draw()
st:draw()
end

function touched(touch)
st:touched(touch)
end

--# Smoke
Smoke = class()

function Smoke:init(killDistance)
self.particles = {}
self.kill = killDistance
end

-- 1 = color, 2 = direction, 3 = start position, 4 = current positiom
local pos = table.maxn(self.particles) +1
self.particles[pos] = {}
self.particles[pos][1] = vec4(255,145,0,255)
self.particles[pos][2] = direction
self.particles[pos][3] = position
self.particles[pos][4] = position
end

function Smoke:draw()
for p = 1,  table.maxn(self.particles) do
if self.particles[p][4]:dist(self.particles[p][3]) < self.kill then

fill(255, 115, 0, 255)
ellipse(self.particles[p][4].x, self.particles[p][4].y, WIDTH/10)
self.particles[p][4] = self.particles[p][4] + self.particles[p][2]
else
print(self.particles[p][4]:dist(self.particles[p][3]))
print(table.maxn(self.particles).."s2")
table.remove(self.particles, p)
print(table.maxn(self.particles).."s1")

end
end
end

function Smoke:touched(touch)
-- Codea does not automatically call this method
end

--# SmokeTest
--For testing and demonstration of smoke class. Remove in finished project!
SmokeTest = class()

function SmokeTest:init()
self.delay = 1
self.smoke = Smoke(300)
end

function SmokeTest:draw()
background(0, 149, 255, 255)
self.smoke:draw()
end

function SmokeTest:touched(touch)
if touch.state == BEGAN or MOVING then
if self.delay == 5 then
self.delay = 1
else
self.delay = self.delay + 1
end
end
end

``````

you’re removing the item from the table in the middle of a for loop. So when it gets to the last entry in the loop it finds there’s nothing there. You either need to use an iterator like `ipairs` (which will request the next entry in the table if it exists each run through the loop) or loop backwards. Also you can use `#` instead of `table.maxn`. Try this in `draw`:
`for p = #self.particles, 1 , -1 do`

Thank you! I was thinking about this completely wrong, figuring the oldest entry was the highest index in the table. Thanks!

It depends on how you add things to the table. `table.insert(myTable, value)` defaults to adding items at the position `#myTable+1`, it’s the same as `myTable[#myTable+1]=value`. But you could insert things at the front of the table by specifying position 1, `table.insert(myTable, 1, value)`, then the oldest entry would be highest. Either way though, when you `table.remove` all items above the one deleted move down one position, and the table length decreases by one. But in your original code, you’ve already given the `for` loop an instruction based on the length of the table before you removed an element, so the loop goes past the end of the table and crashes. By the way, there is a dedicated `color(r,g,b,a)` wrapper, don’t use a `vec4`

If I may add my 2c worth of code change suggestions, here’s a rewrite. Not sure I didn’t introduce bugs, but just wanted to share how I would have written it, with some comments.

``````--# Main

function setup()
displayMode(FULLSCREEN)
st = SmokeTest()
end

function draw()
st:draw()
end

function touched(touch)
st:touched(touch)
end

--# Particle
---- Creating a class for the particle doesn't cost much, and allows to
---- really separate things that only depend on the particle itself
---- from more global things.
Particle = class()

function Particle:init(col,direction,position)
self.col = col
self.direction = direction
self.start = position
self.current = position
self.alive = true -- make the particle aware of whether it is still alive or not
en

---- this may appear in different places, so why not add it as a function on particle?
function Particle:distance()
return self.current:dist(self.start)
end

---- having the draw() function on the particle instead of inside the
---- smoke class will allow you to create particles outside of the
---- smoke class and display them, which may make debugging easier
---- (for instance, if the 'touch' features seam tricky, you can just manually
---- create a Particle using hardcoded values)
function Particle:draw()
print("Drawing")
if self.alive then -- only draw if alive
pushStyle()        --- better to pushstyle before changing fill
fill(255, 115, 0, 255)
ellipse(self.current.x, self.current.y, WIDTH/10)
self.current = self.current + self.direction
popStyle()         --- and popstyle when you are done so you revert to the previous fill color
end
end

--# Smoke
Smoke = class()

function Smoke:init(killDistance)
self.particles = {}
self.kill = killDistance
end

-- not the cleanest, but a standard pattern to add stuff to a table is t[#t+1]=v
self.particles[#self.particles+1] = Particle(vec4(255,145,0,255),direction,position)
end

function Smoke:draw()
for i,p in ipairs(self.particles) do
if p ~= nil then
if p.alive and (p.distance() >= self.kill) then
print(p.distance())
print(#self.particles.."s2")
table.remove(self.particles, i)
print(#self.particles.."s1")
end
p:draw()
end
end

--# SmokeTest
--For testing and demonstration of smoke class. Remove in finished project!
SmokeTest = class()

function SmokeTest:init()
self.delay = 1
self.smoke = Smoke(300)
end

function SmokeTest:draw()
background(0, 149, 255, 255)
self.smoke:draw()
end

function SmokeTest:touched(touch)
if touch.state == BEGAN or MOVING then
if self.delay == 5 then
self.delay = 1
else
self.delay = self.delay + 1
end
end
end

``````

@joelhoro - very helpful, thank you. Welcome to the forum! :-h

Thanks. I’ll put some of this into my code. It’s quite a bit different already than the version I posted earlier, but lots of these ideas will still work. And welcome to the forum!

@joelhoro welcome to the forum

I decided to give your code a try, and took some time to get the errors out of it (yes, we all do that sometimes, coding something and not testing it xd)

1. the Particle:init isn’t completely closed (line 28) there’s ‘en’ instead of ‘end’

2. the Smoke:draw has 1 end short (if looking at the format, it would be the “if p ~= nil” one that isn’t closed)

3. in the Smoke:draw, you call the function “p.distance” 2 times, it should be “p:distance” to make it work

Note that I’m not trying to break anyone down, but just trying to help

Apologies for the few typos. I first typed this in Codea then copy pasted to my browser and that’s when I added a few remarks and more changes. Hopefully you didn’t waste too much time fixing these, but what I wanted to get across were the ideas of factoring the code in smaller pieces.

And thx all for the warm welcome!