Phyisc balls and distance joints

Hi,
I’ve a rather stupid question.
I create two physic bodies CIRCLE of radius R=10 and link them with a physics joint DISTANCE anchored at each ball’s body.position with a distance length of 2body.radius
Then I draw these bodies as ellipse(0,0,2
body.radius) with a strokewidth(1).

However, the two circles are (just) not touching each other. Why?

And furthermore, what is wrong with my code (below) that it doesn’t update the balls based on the parameter?
(If I use math.random() instead, the updates first work and then suddenly stop.)

-- My Test 

function setup()
    parameter.number("LinkL",0,500,105)
    
    b1 = physics.body(CIRCLE,10)
    b1.x = 300
    b1.y = 300
    b2 = physics.body(CIRCLE,50)
    b2.x = 400
    b2.y = 300
  physics.gravity(0,0)
    
    li = physics.joint(DISTANCE,b1,b2,b1.position,b2.position)
    li.length = b1.radius + b2.radius
end

function draw()
    li.length = LinkL
    --li.length = math.random(100,500)
    print(li.length)
    background(212, 211, 212, 255)    
    drawBody(b1)
    drawBody(b2)
    drawLink(li)
end

function drawBody(body)
    pushStyle()
    pushMatrix()
    
    stroke(31, 75, 31, 255)
    translate(body.x, body.y)
    rotate(body.angle)
    if ( body.shapeType == CIRCLE) then
        strokeWidth(1.0)
        ellipse(0,0,2*body.radius)
    end
    
    popMatrix()
    popStyle()
end

function drawLink(link)
    pushStyle()
    pushMatrix()
    stroke(0,0,0)
    strokeWidth(2)
    
    line( link.anchorA.x, link.anchorA.y, link.anchorB.x, link.anchorB.y )
       
    popMatrix()
    popStyle()
    
end

@Bejoscha Add this line at the end of draw to give one of the balls a little velocity. Then try the parameter slider.

b2.linearVelocity=vec2(0,1)

@Bejoscha I haven’t played with the physics joints for a long time. I think the purpose of the DISTANCE joint is to keep 2 objects connected at some distance. As one of the objects moves, the other will follow at the connected distance.

Yes, I wanted to use it as a spring-type connection. Essentially I want to recreate some code I once did in Processing, just to learn Luna. I could recreate my Ball and Spring classes from scratch but I thought if there is already a physics library it would be better to use that.
Your code line did fix the parameter. However, does this mean the distance link acts only if one of the bodies is moving? It seems so. (Is it event triggered?)

The other issue - the “not quite touching” drawing is also annoying. Is it a rounding issue? Or am I missing something?

Ha! My own comment make me remember that I ‘be seen some body parameter that might be related. And indeed, setting sleepingAllowed = false Does the trick.

Remains the drawing issue… Any comment here?

@Bejoscha sleepingAllowed, I remember it well, now. Like I said, I haven’t played with the physics code for quite awhile and totally forgot about that. As for the ellipse drawing, the size of the ellipse isn’t quite what gets set. I don’t remember if something can be set or if you just have to add 1 or 2 to the size. I would have to play with some collision code to see if collisions happen at the correct sizes or if that’s off a little.

It seems the collisions with FLAT surfaces are spot-on. It is the collisions between two circles which is off. (Also in the other example code.) But that’s a bit of a shame, because it means I cannot simply draw a little larger - it would look funky with flat surfaces.

Hmm, maybe I port my own code. But it feels kind of like reinventing the wheel if there is already some library - with possibly more speed optimized code than I have.

@Bejoscha In the below code, even though the circle sizes aren’t correct, when the code runs you can’t tell there is a slight difference.

function setup()
    fill(255, 0, 0, 255)
    b1 = physics.body(CIRCLE,10)
    b1.position=vec2(300,400)
    b1.restitution=1
    b2 = physics.body(CIRCLE,50)
    b2.type=STATIC
    b2.position=vec2(300,100)
end

function draw()
    background(212, 211, 212, 255)    
    drawBody(b1)
    drawBody(b2)
end

function drawBody(body)
    ellipse(body.x,body.y,2*body.radius)
end

Yes, the problem comes when they come to a rest like in the modified physics example below

-- Simple Physics

-- Use this function to perform your initial setup
function setup()
    print("Hello Physics!")
    
    print("Touch the screen to make boxes")
    parameter.boolean("Circle")
    -- Table to store our physics bodies
    bodies = {}
    
    -- Create some static boxes (not effected by gravity or collisions)
    local left = makeBox(WIDTH/4, HEIGHT/2, WIDTH/3, 15, -30)
    left.type = STATIC
    
    local right = makeBox(WIDTH - WIDTH/4, HEIGHT/2, WIDTH/3, 15, 30)
    right.type = STATIC
    
    local floor = maeekeBox(WIDTH/2, 10, WIDTH, 20, 0)
    floor.type = STATIC
    
    table.insert(bodies, left)
    table.insert(bodies, right)
    table.insert(bodies, floor)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color
    background(40, 40, 50)
    
    -- Draw all our physics bodies
    for k,body in pairs(bodies) do
        drawBody(body)
    end
end

function touched(touch)
    -- When you touch the screen, create a random box
    if touch.state == BEGAN then
        if Circle then
        table.insert(bodies, makeCircle(touch.x, touch.y, math.random(10, 25))) 
        else
        table.insert(bodies, makeBox(touch.x, touch.y, math.random(25, 50), math.random(25, 50), 0))
        end
    end
end

-- Helper function to create a box using a polygon body
function makeBox(x,y,w,h,r)
    -- Points are defined in counter-clockwise order
    local body = physics.body(POLYGON,vec2(-w/2, h/2),
    vec2(-w/2, -h/2), vec2(w/2, -h/2), vec2(w/2, h/2))
    
    -- Set the body's transform (position, angle)
    body.x = x
    body.y = y
    body.angle = r
    
    -- Make movement smoother regardless of framerate
    body.interpolate = true
    
    return body
end

function makeCircle(x,y,r)
    local circle = physics.body(CIRCLE, r)
    -- enable smooth motion
    circle.interpolate = true
    circle.x = x
    circle.y = y
    circle.restitution = 0.25
    circle.sleepingAllowed = false
    return circle
end

-- Helper function to draw a physics body
function drawBody(body)
    -- Push style and transform matrix so we can restore them after
    pushStyle()
    pushMatrix()
    
    strokeWidth(5)
    stroke(148, 224, 135, 255)
    translate(body.x, body.y)
    rotate(body.angle)
    
    -- Draw body based on shape type
    if body.shapeType == POLYGON then
        strokeWidth(3.0)
        local points = body.points
        for j = 1,#points do
            a = points[j]
            b = points[(j % #points)+1]
            line(a.x, a.y, b.x, b.y)
        end
    elseif body.shapeType == CHAIN or body.shapeType == EDGE then
        strokeWidth(3.0)
        local points = body.points
        for j = 1,#points-1 do
            a = points[j]
            b = points[j+1]
            line(a.x, a.y, b.x, b.y)
        end
    elseif body.shapeType == CIRCLE then
        strokeWidth(3.0)
        line(0,0,body.radius-3,0)
        ellipse(0,0,body.radius*2)
    end
    
    -- Restore style and transform
    popMatrix()
    popStyle()
end

@Bejoscha You can do something like this. Multiply the radius by 2.15 or whatever value gives the best view. It doesn’t affect the collision distance, just the display for the circle.

    elseif body.shapeType == CIRCLE then
        strokeWidth(3.0)
        line(0,0,body.radius-3,0)
        ellipse(0,0,body.radius*2.15)
    end

Yeah, but the problem is that it then looks odd for contacts with straight features. I think it really can only be fixed in the library…