messing around with "physics labs" examples

I’ve been trying this for the best part of today…

In physics lab’s test6, for example, I’m trying to swap wheels (I know, this is odd, but that’s the simplest way to explain what I’m struggling with…)

If I touch the front wheel, I want the large rear wheel to take the place of the smaller, front wheel. I want them to keep all their respective properties, etc.

Is their a way to do this?

Would swapping bodies in the PhysicsDebugDraw tab do the trick? If so, how to accomplish this? I’m stuck here… :frowning:

Cheers!

I’m guessing you’d need to swap the positions of the wheels wherever they are used (which seems to be in leftPos, leftWheel, and self.leftJoint) with the values for the right wheel

you can swap leftPos for example, like this
leftPos,rightPos=rightPos,leftPos

Thanks! I’m trying to get this to work, some quick attempts weren’t successfull but I’m still on it. I guess my main issue is to really understand how bodies work, what’s the importance of their orders in the bodies table, as well as the connection to what is drawn on top. Cheers!

Ok, so I tried several different things, and none seem to work correctly. The closest I’m getting to effectively swap two bodies (let me call them b1 et b2) in a physics simulation made of joints and circles is when I:

  1. list all existing joints connected to body b1 (I’ll call the list c1)
  2. list all existing joints connected to object b2 (I’ll call the list c2)
  3. erase all connections (in the simulation) from arrays c1 et c2
  4. rebuild c1 connections using object b2 as a starting point
  5. rebuild c2 connections using object b1 as a starting point
  6. swap x,y coordinates between b1 and b2

I’m having several issues though:

  1. this works most of the time… Results are sometimes odd, and I’m suspecting that removing joints doesn’t really work the way it should. I’ve tried joint:remove()
  2. I consider myself a rather bad coders, I code a bit here and there, but my methods are almost always the most convoluted, which leads me to think that here must be a most elegant, less tedious and, more importantly, less buggy way to accomplish this apparently simple operation in Codea.
    Don’t you think?

Here’s my code :

function PhysicsDebugDraw:swapBodies(b1,b2)
c1 = {}
c2 = {}

c1 = b1.joints

for i,v in pairs(c1) do
    if v.bodyA.id == b2.id or v.bodyB.id == b2.id then
        table.remove(c1,i)
    end
end

for i,v in pairs(c1) do
    if v.bodyB.id == b1.id then
        table.remove(c1,i)
        local edge = createEdge(v.bodyB,v.bodyA) -- THIS BUILT A 'DISTANCE' TYPE CONNECTION BETWEEN TWO BODIES
        table.insert(c1,edge)
    end
end

c2=b2.joints

for i,v in pairs(c2) do
    if v.bodyA.id == b1.id or v.bodyB.id == b1.id then
        table.remove(c2,i)
    end
end

for i,v in pairs(c2) do
    if v.bodyB.id == b2.id then
        table.remove(c2,i)
        local edge = createEdge(v.bodyB,v.bodyA)
        table.insert(c2,edge)
    end
end

-- dewire
print(table.getn(self.joints) .. " liens en tout")
print(table.getn(c1) + table.getn(c2) .. " Ã  enlever")
for i,v in pairs(c1) do
    table.remove(self.joints,i)
    collectgarbage() -- DOES THIS EVEN DO ANYTHING?
    --v:destroy() -- DOESN'T SEEM TO WORK 
end
for i,v in pairs(c2) do
    table.remove(self.joints,i)
    collectgarbage()
    --v:destroy()
end

-- rewire
for i,v in pairs(c1) do
    local edge = createEdge(b2,v.bodyB)
end

for i,v in pairs(c2) do
    local edge = createEdge(b1,v.bodyB)
end

temp = b1.position
b1.position = b2.position
b2.position = temp

end


end of code snippet

Try something like this:

See code below.

Tested the above code with 2 groups of 3 bodies connected by distance joints in a chain manner. It swapped perfectly.

Here is the full project I used to test the above code:


--# Main
-- physics

-- Use this function to perform your initial setup
function setup()
    c1 = physics.body(CIRCLE,25)
    c1.position = vec2(200,500)
    c2 = physics.body(CIRCLE,25)
    c2.position = vec2(200,450)
    c3 = physics.body(CIRCLE,25)
    c3.position = vec2(200,400)
    c4 = physics.body(CIRCLE,25)
    c4.position = vec2(250,450)
    physics.joint(DISTANCE,c1,c2,c1.position,c2.position)
    physics.joint(DISTANCE,c2,c3,c2.position,c3.position)
    physics.joint(DISTANCE,c2,c4,c2.position,c4.position)
    d1 = physics.body(CIRCLE,25)
    d1.position = vec2(600,500)
    d2 = physics.body(CIRCLE,25)
    d2.position = vec2(600,450)
    d3 = physics.body(CIRCLE,25)
    d3.position = vec2(600,400)
    physics.joint(DISTANCE,d1,d2,d1.position,d2.position)
    physics.joint(DISTANCE,d2,d3,d2.position,d3.position)
    c1.active = false
    c2.active = false
    c3.active = false
    c4.active = false
    d1.active = false
    d2.active = false
    d3.active = false
    parameter.action("Swap", swap)
    body1 = {c1}
    body2 = {d1}
    getAllConnected(body1, c1)
    getAllConnected(body2, d1)
end

function swap()
    swapPosition(c1,d1)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    noStroke()

    -- Do your drawing here
    fill(0, 0, 255, 255)
    for _,v in pairs(body1) do
        ellipse(v.x, v.y, 15)
    end
    fill(255, 0, 0, 255)
    for _,v in pairs(body2) do
        ellipse(v.x, v.y, 15)
    end
end


--# Swap
function swapPosition(b1,b2)
    local x = b2.x - b1.x
    local y = b2.y - b1.y
    bodies1 = {b1}
    bodies2 = {b2}
    
    getAllConnected(bodies1, b1)
    getAllConnected(bodies2, b2)
    
    for _,v in pairs(bodies1) do
        v.x = v.x + x
        v.y = v.y + y
    end
    
    for _,v in pairs(bodies2) do
        v.x = v.x - x
        v.y = v.y - y
    end
end

function getAllConnected(bodies, b)
    for _,v in pairs(b.joints) do
        local intable = false
        for _,vv in pairs(bodies) do
            if v.bodyB == vv then
                intable = true
            end
        end
        if not intable then
            table.insert(bodies, v.bodyB)
            getAllConnected(bodies, v.bodyB)
        end
    end
end

I added a 4th body to one of the 2 bodies so you can verify it is actually swapping all connected bodies.

As you can see above, the getAllConnected function will work for drawing your bodies as well. Just don’t forget to manually add the body being used to getAllConnected as it is not added to the table by the function, only the bodies recursively connected to it. However, if your bodies make a complete circle, then it will be recursively added, but manually adding it will not have it added twice, so I still suggest manually adding it.

Oh, that looks really nice. Thank you so much indeed. I’ve run your standalone example, and I have a hard time seeing how the code would behave with connections. Does it swap positions only, or also the connections that go with each swapped bodies (ok, that’s not clear at all… in other words, in swapping A and B, does B inherits A’s former connections, and vice versa? like on this very artistic rendering of what I’m looking to accomplish: https://www.dropbox.com/s/8u7yt4y2fnhppcp/Untitled%20artwork.jpg )

@Rodolphe, I must have misunderstood what you were originally asking. My code will swap the positions of 2 separate bodies, each having multiple body connections of their own (the 2 bodies being swapped aren’t connected at all). The recursive function is to make sure you get all the bodies attached to body1 and then all the bodies attached to body2 and swap positions. Like if you had created 2 separate human bodies, it would swap the positions of the 2 people.

The only way to accomplish what is shown in your drawing is to do it how you already started to. You would have to figure out the bodies involved (my recursive function would still work for this) and then recreate each of them with their new connections.

Back to the human example. So you are basically trying to swap an arm with a leg and make sure it reconnects correctly?

Ah ok @Slashin8r, this is what I thought. Thank you so much anyway, I did learn a few trick from your code. I am indeed trying to swap an arm with a leg (how odd does that sound… :D). I’ll keep on working on my not-really-elegant-code then, using some of your recursive code to improve it (cheers for that!).

By the way, what’s the best way to effectively and instantly remove a joint from a physics simulation? removing the joint from the joints list and Garbage collecting? using destroy() on the joint? Something else?

Here is a function that swaps the bodies and sets the new joints.


--# Main
-- physics

-- Use this function to perform your initial setup
function setup()
    c1 = physics.body(CIRCLE,25)
    c1.position = vec2(200,500)
    c2 = physics.body(CIRCLE,25)
    c2.position = vec2(200,450)
    c3 = physics.body(CIRCLE,25)
    c3.position = vec2(200,400)
    c4 = physics.body(CIRCLE,25)
    c4.position = vec2(250,450)
    physics.joint(DISTANCE,c1,c2,c1.position,c2.position)
    physics.joint(DISTANCE,c2,c3,c2.position,c3.position)
    physics.joint(DISTANCE,c2,c4,c2.position,c4.position)
    d1 = physics.body(CIRCLE,25)
    d1.position = vec2(600,500)
    d2 = physics.body(CIRCLE,25)
    d2.position = vec2(600,450)
    d3 = physics.body(CIRCLE,25)
    d3.position = vec2(600,400)
    physics.joint(DISTANCE,d1,d2,d1.position,d2.position)
    physics.joint(DISTANCE,d2,d3,d2.position,d3.position)
    c1.active = false
    c2.active = false
    c3.active = false
    c4.active = false
    d1.active = false
    d2.active = false
    d3.active = false
    parameter.action("Swap", swap)
    body1 = {c1}
    body2 = {d1}
    getAllConnected(body1, c1)
    getAllConnected(body2, d1)
end

function swap()
    print("Joints Before Swap")
    print("c2")
    for _,v in pairs(c2.joints) do
        local b
        if c2 == v.bodyA then
            b = v.bodyB
        else
            b = v.bodyA
        end
        print(b.x,b.y)
    end
    print("d2")
    for _,v in pairs(d2.joints) do
        local b
        if d2 == v.bodyA then
            b = v.bodyB
        else
            b = v.bodyA
        end
        print(b.x,b.y)
    end
    swapBodies(c2,d2)
    print("Joints After Swap")
    print("c2")
    for _,v in pairs(c2.joints) do
        local b
        if c2 == v.bodyA then
            b = v.bodyB
        else
            b = v.bodyA
        end
        print(b.x,b.y)
    end
    print("d2")
    for _,v in pairs(d2.joints) do
        local b
        if d2 == v.bodyA then
            b = v.bodyB
        else
            b = v.bodyA
        end
        print(b.x,b.y)
    end
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    noStroke()

    -- Do your drawing here
    fill(0, 0, 255, 255)
    for _,v in pairs(body1) do
        ellipse(v.x, v.y, 15)
    end
    fill(255, 0, 0, 255)
    for _,v in pairs(body2) do
        ellipse(v.x, v.y, 15)
    end
end


--# Swap
function swapBodies(b1,b2)
    joints1 = {}
    joints2 = {}
    
    for _,v in pairs(b1.joints) do
        local b
        if b1 == v.bodyA then
            b = v.bodyB
        else
            b = v.bodyA
        end
        table.insert(joints1, b)
        v:destroy()
    end
    
    for _,v in pairs(b2.joints) do
        local b
        if b2 == v.bodyA then
            b = v.bodyB
        else
            b = v.bodyA
        end
        table.insert(joints2, b)
        v:destroy()
    end
    
    b1.position,b2.position = b2.position,b1.position
    
    for _,v in pairs(joints1) do
        physics.joint(DISTANCE,b2,v,b2.position,v.position)
    end
    
    for _,v in pairs(joints2) do
        physics.joint(DISTANCE,b1,v,b1.position,v.position)
    end
end

function getAllConnected(bodies, b)
    for _,v in pairs(b.joints) do
        local intable = false
        for _,vv in pairs(bodies) do
            if v.bodyB == vv then
                intable = true
            end
        end
        if not intable then
            table.insert(bodies, v.bodyB)
            getAllConnected(bodies, v.bodyB)
        end
    end
end

The swapBodies function does the work and the swap function verifies it. getAllConnected is now only used to draw the bodies.

Great great great, thanks once again for you help, I’ll try it later today.

Woohoo! It took me a while but I finally managed to get your excellent example to work in my project. Thanks a LOT!