Anyone help with a puzzling error

First of all thanks for such a wonderful app and especial thanks to Ignatz for his tutorials, without which I wouldn’t have got anywhere, but can anyone explain the problem with the polygon collision code below. Sometimes it seems to work fine, while at other times it generates an error saying ‘attempt to index field, a nil value’

Has anyone got any thoughts because I’m a bit stumped!

--- poly2
function setup()
physics.iterations(20,20)
poly={} -- an empty table to fill with the polygons created by touches
loop=0  -- the number of polygons, initially zero
parameter.number("restitution",0,1,1)
parameter.integer("min_length",10,100,20)  
parameter.integer("max_length",15,200,30)
parameter.integer("min_edges",3,50,3)
parameter.integer("max_edges",3,50,10)
parameter.number("friction",0,1,0)
parameter.integer("side_variation_factor",0,20)



w1 = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0),1) 
w2 = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT),1) 
w3 = physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT),1)
w4 = physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT),1)
end


function touched(touch)
if touch.state==ENDED then loop = loop + 1 
    vx=touch.deltaX*50
    vy=touch.deltaY*50
    makepoly(touch.x,touch.y,vx,vy) 
    end
end


function collide(contact)
if contact.state == BEGAN then
  ca=contact.bodyA.info
  cb=contact.bodyB.info
      if contact.bodyA.mass~=0 and contact.bodyB.mass~=0 then
      print("Hit between "..ca.." and "..cb)
      sound(SOUND_EXPLODE, math.random(2500,2510))   
      poly[ca].kill='y'
      poly[cb].kill='y'
      end
end
end


function makepoly(x,y,vx,vy) 
count=math.random(min_edges,max_edges) 
r=math.random(min_length,max_length) 
a=0 
d=(2*math.pi)/count 
points={} 
for i=1,count do 
    v=vec2(r,0):rotate(a) + vec2(math.random(- side_variation_factor,side_variation_factor),math.random(-side_variation_factor,side_variation_factor)) 
    a=a+d
    table.insert(points,v)
end

--the code below picks up the table of vec2s and makes a physics body from them
poly[loop]=physics.body(POLYGON,unpack(points))
poly[loop].x=x
poly[loop].y=y
poly[loop].restitution=restitution
poly[loop].friction=friction
poly[loop].color=color(math.random(50,255),math.random(50,255),math.random(50,255),255)
poly[loop].vertices=points
poly[loop].sleepingAllowed=false
poly[loop].interpolate=true
poly[loop].angularDamping=1.5
poly[loop].linearDamping=0
poly[loop].linearVelocity=vec2(vx,vy)
poly[loop].info=loop
poly[loop].kill='n'
end

function draw()
background(4, 4, 4, 255)
physics.gravity(Gravity)
polylines()
end

function polylines()
for j,v in pairs(poly) do
    if poly[j].kill=='y' then
        poly[j]:destroy()
        poly[j]=nil
        table.remove(poly,j)
        
    else
        pushMatrix()
        pushStyle()
        poly[j].restitution=restitution
        translate(poly[j].x,poly[j].y)
        rotate(poly[j].angle)
        strokeWidth(2)
        stroke(poly[j].color)
        points=poly[j].vertices
            for m=1,#points do
                a=points[m]
                b=points[(m%#points)+1]
                line(a.x,a.y,b.x,b.y)
            end
        popStyle()
        popMatrix()
    
    
   end
 end       
end

@Tmon In makepoly(), you’re setting “info” to “loop” which is a specific offset in the table poly. In polylines(), you remove entries from the table. You are getting the error because in collide() you’re setting “kill” to “y” at an offset “ca” or “cb” that doesn’t exist anymore. Let me know if you need a better explanation.

@Tmon Here’s a better explanation. Say you create 10 objects that haven’t collided yet. Those 10 objects have “info” set to the “loop” values 1 thru 10. As the objects collide, you remove them from the table. Say the objects 2 thru 9 collide and are removed from the “poly” table. There are now 2 entries left in the “poly” table, but one of them has “info” set to 10. When you use 10, you get an error because there isn’t anything at offset 10.

@Tmon - I suggest that in makepoly, you use a local variable p to set up your new physics body, ie

local p=physics.body(....)
p.x=x
etc...then when you're done..
table.insert(poly,p)

Also, when you destroy objects, don’t set the table value to nil, because your next line removes it anyway, ie “poly[j]=nil” is not needed.

Glad to hear you enjoy my posts, it’s hard to know sometimes if anyone is getting value from them
:">

Thanks for the ideas guys. I’m still puzzled though - if you have a table of physics objects how can you label them so that the collide function knows which of the items in the table is colliding? How can you pass this information so that destroy() knows which physics objects in a table to destroy?
Thanks for the help so far - any insight will be much appreciated!

@Tmon You have the x,y values of the objects in a table, like poly. Then when the collision happens, you get the x,y values of the bodyA and bodyB objects. You then loop thru the poly table and compare the poly x,y values to the bodyA and bodyB x,y values.When you get a match, those are the objects in the table that collided and you destroy them.

Thanks Dave - it’s seems straightforward after someone else points it out to you!
I think I’ve come up with a simple solution though.

The problem I had was how to create a stable numbering system for a table when new objects are being added and random objects are being removed.
One (perhaps inelegant) solution is to stop lua from removing the table objects at all. By commenting out ‘poly[j]=nil’ and ‘table.remove(poly,j)’ lines above it works fine.
I think this stops lua dropping all the table entries down to condense the table and therefore the labelling system I used stays intact!
All help much appreciated.

@Tmon That will work, but the table keeps getting larger. I guess in this program that won’t matter that much, so your solution is an easy way around the problem. But as you write larger and more complex programs, your won’t want to leave unused objects in the table.

@Tmon - there is another solution that I think will work well for you. Physics bodies have a property called info, which you can use to store anything - such as the table position of that physics object. This enables you to identify which bodies collided without having to loop through all of them.