Confusion with Physics

Hey all,

I’m have two issues with the new physics that are both confusing me. Maybe I’m doing something wrong here?

  1. No friction - when I apply a one time force to a body (object:applyForce(vec2(1,1))) that object continues moving forever, even when I first set it’s friction property to 1, 10, 100, anything. Does that make sense? How can I have the body gradually come to a stop?

  2. Can’t alter linearVelocity - partly in trying to get around the first issue of no friction, I was trying to manually alter the linear velocity but found that my effort was ignored no matter what I changed it to for the body. When you apply a force does it then ignore the linearVelocity? How should I do something like reverse the velocity after a force was applied?

Any help would be appreciated, thanks!

  • Mike

on (1), I believe for friction to work you need two objects. If you only have one object, then there’s no friction applied (ie pretend objects live in space and there’s no air around them)

(2), I’ve managed to set angularVelocity and get that to work, but haven’t tried to play with linearVelocity. Surprised it doesn’t work. Does it work if you just create one body, set the velocity and don’t apply any force to it?

I have a question too - when you apply a force, how long is that force applied for? how much work does it do on the body?

I suspect it is not implemented yet. The code below shows two boxes, where the friction of the bottom one and its ground can be varied. There are walls on both sides (not drawn), and the boxes don’t bounce (restitution = 0). A force is applied to the boxes everytime you tap ( on the right to move the boxes to the right, on the left to move them to the left. Notice that the boxes stay on the same coordinate, no matter what the friction settings.



-- Use this function to perform your initial setup
function setup()
    --ground=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
    ground=physics.body(POLYGON,vec2(0,-10),vec2(WIDTH,-10),vec2(WIDTH,0),vec2(0,0))
    ground.x=0
    ground.y=0
    ground.type=STATIC
    ground2=physics.body(POLYGON,vec2(0,-10),vec2(WIDTH,-10),vec2(WIDTH,0),vec2(0,0))
    ground2.x=0
    ground2.y=100
    ground2.type=STATIC
    lwall=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    rwall=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))
    box=physics.body(POLYGON,vec2(0,0),vec2(20,0),vec2(20,20),vec2(0,20))
    box.x=0
    box.y=50
    box.sleepingAllowed=false
    box2=physics.body(POLYGON,vec2(0,0),vec2(20,0),vec2(20,20),vec2(0,20))
    box2.x=0
    box2.y=150
    box2.sleepingAllowed=false
    parameter("friction",0,100,0.2)
end

function touched(touch)
    if (touch.state==BEGAN) then
        if (touch.x>WIDTH/2) then
            box:applyForce(vec2(50,0))
            box2:applyForce(vec2(50,0))
        else
            box:applyForce(vec2(-50,0))
            box2:applyForce(vec2(-50,0))
        end
    end
end

function drawObject(obj)
    pushMatrix()
    translate(obj.x,obj.y)
    rotate(obj.angle)
    local points = obj.points
    for j = 1,#points do
        a = points[j]
        b = points[(j % #points)+1]
        line(a.x, a.y, b.x, b.y)
    end
    popMatrix()
end

-- This function gets called once every frame
function draw()
    box.friction=friction
    ground.friction=friction
    -- This sets a dark background color 
    background(0, 0, 0, 255)

    -- This sets the line thickness
    strokeWidth(5)
    line(0,0,WIDTH,0)
    -- Do your drawing here
    stroke(255, 255, 255, 255)
    drawObject(ground)
    drawObject(ground2)
    
    stroke(31, 0, 255, 255)
    drawObject(box)
    drawObject(box2)
end


Herwig, does it work if instead of EDGE for the walls you change to very thin rectangular POLYGON bodies?

Actually the ground (where all the sliding is done on) is a not so thin POLYGON, only the side walls are EDGEs. I also tried EDGE on the ground (first), but got the same result. Any comments from @TLL?

@Neztec

  1. Friction does work when two bodies are touching. If you have an object floating through space, try setting linearDamping and angularDamping to cause them to come to a gradual stop (something like 0.1-0.5). Higher values will slow them down faster.

  2. I’m not sure why linearVelocity isn’t working. Make sure you object hasn’t gone to sleep as this might stop linearVelocity from having an effect.

@Herwig
Changing friction does work, however, when two objects collide in Box2D their contacts store the friction associated with the two bodies. Since Box2D caches these contacts while the two objects are still touching, updating the friction on the bodies has no effect (between that specific pair) until they stop touching. I can probably fix this, but I will need to look into the code. A workaround you can use for now, is when you change the friction on a body, do the following:

box.friction = 10
box.active = false
box.active = true

This will reset the contacts on the body and thus use the new friction value.

@ruilov
Forces are assumed to be continuous, so one frame of force is equivalent to 1/60th of a second of force. If you use applyImpulse, this is an instantaneous impulse, which for the same values will be much stronger, effecting velocity directly.

Hope this clears things up a bit for everyone.

Thanks John, it does help

To clarify further on impulses, when I apply an impulse does it just add that numeric value to the velocity, or is there a unit conversion? (sorry I’m away from my ipad right now otherwise I’d check). If velocity was (2,3) and you apply an impulse of (4,5) does the velocity instantaneously become (6,8) ?

Hmm,

I just realised that applyImpulse isn’t in there. I’ll add it next update. For now you can just multiply applyForce by 60. The units will technically be in newtons, so you could then multiply it by body.mass, which would make it an instantaneous acceleration, which would directly change the velocity like you describe.

Thanks @John for clearing that up. Works like a charm now! Revised code below:

-- Friction example
-- Herwig Van Marck
function setup()
    --ground=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
    ground=physics.body(POLYGON,vec2(0,-10),vec2(WIDTH,-10),vec2(WIDTH,0),vec2(0,0))
    ground.x=0
    ground.y=0
    ground.type=STATIC
    ground2=physics.body(POLYGON,vec2(0,-10),vec2(WIDTH,-10),vec2(WIDTH,0),vec2(0,0))
    ground2.x=0
    ground2.y=100
    ground2.type=STATIC
    lwall=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    rwall=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))
    box=physics.body(POLYGON,vec2(0,0),vec2(20,0),vec2(20,20),vec2(0,20))
    box.x=0
    box.y=50
    box.sleepingAllowed=false
    box2=physics.body(POLYGON,vec2(0,0),vec2(20,0),vec2(20,20),vec2(0,20))
    box2.x=0
    box2.y=150
    box2.sleepingAllowed=false
    parameter("friction",0,1,0.2)
    prevFriction=0.2
    print("The parameter changes the friction of the bottom box")
    print("Tapping moves both boxes with the same force")
end

function touched(touch)
    if (touch.state==BEGAN) then
        if (touch.x>WIDTH/2) then
            box:applyForce(vec2(50,0))
            box2:applyForce(vec2(50,0))
        else
            box:applyForce(vec2(-50,0))
            box2:applyForce(vec2(-50,0))
        end
    end
end

function drawObject(obj)
    pushMatrix()
    translate(obj.x,obj.y)
    rotate(obj.angle)
    local points = obj.points
    for j = 1,#points do
        a = points[j]
        b = points[(j % #points)+1]
        line(a.x, a.y, b.x, b.y)
    end
    popMatrix()
end

-- This function gets called once every frame
function draw()
    if (friction~=prevFriction) then
        box.friction=friction
        box.active=false
        box.active=true
    end
    ground.friction=friction
    -- This sets a dark background color 
    background(0, 0, 0, 255)

    -- This sets the line thickness
    strokeWidth(5)
    line(0,0,WIDTH,0)
    -- Do your drawing here
    stroke(255, 255, 255, 255)
    drawObject(ground)
    drawObject(ground2)
    
    stroke(31, 0, 255, 255)
    drawObject(box)
    drawObject(box2)
end

@John How about the equivalent for angular impulses? If you want to change the angular velocity from 1 to -1 by applying torque would that then be

applyTorque(-60*2*body.momentOfInertia)

At the moment the inertia property isn’t exposed. I’ll add that for the next release. Otherwise that code would work.

Thanks for the help! Just a note - the linearDamping property isn’t exposed in the docs.

Thanks for reminding me. I’ll fix that.