How can I find references to a given physics body?

I know that body:destroy()` won’t work if there are still any references anywhere to that body.

I am trying to destroy bodies, and it’s not working, and for the life of me I can’t figure out where they’re being referenced.

Is there any way to have a body detect when it’s added to a table—because then I could do a stacktrace and find out where it’s happening—?

@UberGoober When you add a body to a table, you’ll use that table position to destroy it. You can iterate thru the table to destroy everything in the table. If you remove a lot of entries, you have to go thru the table in reverse order because anytime you remove a table entry, the other entries are shifted to fill the empty space. If you iterate the table from beginning to end, when an entry is removed, the next item will fill the empty space and get skipped as you iterate forward thru the table.

PS. I had a lot of examples where I destroyed bodies from a table. If you want one, let me know.

@UberGoober Heres an example of adding bodies to a table and destroying them. There a 2 touched functions. One delete the bodies in a forward direction, the other in reverse. Change the touched function to execute one or the other to demo what I mentioned above about destroying and deleting bodies. Tap the screen to delete the bodies. One deletes them all at once, the other only half each time.

viewer.mode=FULLSCREEN

function setup()
    fill(255)
    tab={}
    physics.body(EDGE,vec2(0,50),vec2(WIDTH,50))
    physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    physics.body(EDGE,vec2(WIDTH,50),vec2(WIDTH,HEIGHT))
    for z=1,300 do
        local b=physics.body(CIRCLE,10)
        b.x=math.random(WIDTH)
        b.y=math.random(HEIGHT)
        table.insert(tab,b)
    end
    
end

function draw()
    background()
    for a,b in pairs(tab) do
        ellipse(b.x,b.y,20)
    end
    text(#tab,WIDTH/2,HEIGHT-50)
end

function touched(t) -- delete table in reverse direction
    if t.state==BEGAN then
        for z=#tab,1,-1 do
            tab[z]:destroy()
            table.remove(tab,z)
        end
    end    
end

function touched(t) -- delete table in forward direction
    if t.state==BEGAN then
        for a,b in pairs(tab) do
            b:destroy()
            table.remove(tab,a)
        end
    end    
end

@dave1707 I think that only matters if you’re using ipairs to iterate?

I’m using pairs though, so technically I’m using keys and not positions to nil them out, I think.

But in any case the problem isn’t getting them out of a single table, I’m doing that just fine, it’s that they must be included in some table I haven’t found yet, buried somewhere in my code, because even when I empty them out of one table successfully, the physics bodies are still in the physics.bodies table.

@UberGoober Only part are removed each time even doing pairs in my above example. I don’t know of any way to find where bodies are hidden. They should only be in whatever table you put them in. If you don’t destroy them, they’ll still remain even though you might not see them.

In my above example, comment out the b:destroy in the last touched function. When you tap the screen, some of the balls disappear but they’re still there as physics bodies.

So unless I’m wrong here, neither of your touched functions will remove bodies that are not indexed by a number, I think. Also mightn’t the second one throw an error if there are any text keys?

Also I thought someTable[3] = nil just places a nil at the 3 index and doesn’t move any of the other numbers. Is that wrong?

@UberGoober If you put a body in the table using a key, then you would use the table with that key when you want to destroy the body. I’m not sure about the nil value. I’ll have to try different things and see what the different results are.

At any rate the real problem is that the bodies are, as you put it, hidden (I love that). They seem to have been put in a table I can’t find.

what’s the reproduction code?

@UberGoober What’s happening that you think you have hidden bodies.

Here’s an example of hidden bodies. I’m creating them in the first for loop but doing nothing with them. Run the code, wait approx 10 sec then tap the screen. You see 300 circles created like the other examples, but they won’t go all the way to the bottom of the screen because that’s where the hidden bodies are. They’re there because you created them even though you’re not doing anything with them.

viewer.mode=FULLSCREEN

function setup()
    fill(255)
    tab={}
    physics.body(EDGE,vec2(0,50),vec2(WIDTH,50))
    physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    physics.body(EDGE,vec2(WIDTH,50),vec2(WIDTH,HEIGHT))
    for z=1,300 do
        b=physics.body(CIRCLE,10)
        b.x=math.random(WIDTH)
        b.y=math.random(HEIGHT)
    end
    
end

function draw()
    background()
    for a,b in pairs(tab) do
        ellipse(b.x,b.y,20)
    end
    text("wait approx 10 seconds then tap the screen",WIDTH/2,HEIGHT-100)
end

function touched(t) -- delete table in reverse direction
    if t.state==BEGAN and #tab==0 then
        for z=1,300 do
            b=physics.body(CIRCLE,10)
            b.x=math.random(WIDTH)
            b.y=math.random(200,HEIGHT)
            table.insert(tab,b)
        end
    end    
end

I’m trying to destroy bodies.

I remove them from every table that they’re in, I destroy them one by one, but the total #physics.bodies doesn’t change.

I’m calling them hidden because I can’t find where in the code they’re being stored, not where they are on the screen.

@UberGoober physics.bodies is a table you can use to destroy anything in it.

I still don’t think they get destroyed if there are references to them extant. Plus the docs say it’s read-only. Is that wrong?

Is there a way to set a meta table globally, like on the table command itself or something?

That way I could track every time something is put into an empty index in every table in the project.

In think you can do that - https://www.lua.org/pil/13.4.1.html

@UberGoober How many tables do you have with bodies in them and how many bodies do you have. You could add an if statement where you add a body and print something or stop the program if you don’t think a body should be added.

@UberGoober Here’s a way you can track down what’s happening. Using the physics.bodies table, you can print information about the bodies you create and where you put them. When I create the physics.body, I add information about what it is and where. Tap the screen to print the info.

viewer.mode=STANDARD

function setup()
    fill(255)
    tab={}
    e1=physics.body(EDGE,vec2(0,50),vec2(WIDTH,50))
    e1.info="edge bottom"
    e2=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    e2.info="edge left"
    e3=physics.body(EDGE,vec2(WIDTH,50),vec2(WIDTH,HEIGHT))
    e3.info="edge right"
    for z=1,10 do
        local b=physics.body(CIRCLE,10)
        b.x=math.random(WIDTH)
        b.y=math.random(HEIGHT)
        b.info="circle "..z.." in table tab"
        table.insert(tab,b)
    end    
end

function draw()
    background()
    for a,b in pairs(tab) do
        ellipse(b.x,b.y,20)
    end
end

function touched(t) 
    if t.state==BEGAN then
        for a,b in pairs(physics.bodies) do
            print(b.info)
        end
    end    
end

@dave1707 I already have things like this, it doesn’t really address the core issue.

See, if I could find the place where the bodies are being added to the table that keeps them from being destroyed, I wouldn’t need a trick to help me find it, right?

Problem is that I haven’t been able to find it, so I’m trying to see if there’s something I can do without that information.

@skar That’s exactly the kind of thing I’m trying to do, but I need to find a way to apply it to all tables by default. Like somehow attach that metamethod to the table creation routine itself, so any table that gets created automatically uses it. Is there any possible way to do that? Again, if I could find just the one specific table that needs it, I wouldn’t need help finding that table, which is the whole point of this in the first place.