Edges Seem Porous

In the code below, if I keep my iPad relatively level, the physics body (and sprite or ellipse) will honor the edges and stay on the screen. If I tilt the iPad so that the physics body hits an edge with some speed, it will often go through the edge. Also, supportedOrientations doesn’t seem to work. I appreciate the help I get here.

function setup()

    displayMode(FULLSCREEN)
    supportedOrientations(LANDSCAPE_RIGHT)

    LeftEdge = physics.body (EDGE, vec2(0, 0), vec2(0, HEIGHT)) 
    RightEdge = physics.body (EDGE, vec2(WIDTH, 0), vec2(WIDTH, HEIGHT))
    BottomEdge = physics.body (EDGE, vec2(0, 0), vec2(WIDTH, 0))
    TopEdge = physics.body (EDGE, vec2(0, HEIGHT-50), vec2(WIDTH, HEIGHT-50))
    LeftEdge.restitution = 1
    RightEdge.restitution = 1
    BottomEdge.restitution = 1
    TopEdge.restitution = 1

    MyBody = physics.body(CIRCLE,40) 
    MyBody.type = DYNAMIC 
    MyBody.x = WIDTH/2
    MyBody.y = 200
    MyBody.gravityScale = 0
    MyBody.restitution = 1

end

function draw()
    background(40, 40, 50)  
    strokeWidth(5) 
    fill(23, 39, 203, 255)
    MyBody.x = MyBody.x + (Gravity.x * 200)      
    MyBody.y = MyBody.y + (Gravity.y * 100)
    -- ellipse(MyBody.x, MyBody.y, 80)
    sprite("Planet Cute:Character Boy", MyBody.x, MyBody.y, 75, 75)
end

Have you tried using the collide(contact) function?

I use collide for some other things but not for edges. The sample code I’ve looked at doesn’t seem to use collide. Should I set up collide to check the edges? I’m a newbie and learning slowly. Thanks.

The problem is your body is moving so fast. Try setting

MyBody.bullet=true

This is specifically designed for objects that may tunnel through edges.

There should be no need to use collide code.

Ignaz, I’ve added the bullet property but still have the problem. Posting the updated code. Thanks.

function setup()

    displayMode(FULLSCREEN)
    supportedOrientations(LANDSCAPE_RIGHT)

    LeftEdge = physics.body (EDGE, vec2(0, 0), vec2(0, HEIGHT)) 
    RightEdge = physics.body (EDGE, vec2(WIDTH, 0), vec2(WIDTH, HEIGHT))
    BottomEdge = physics.body (EDGE, vec2(0, 0), vec2(WIDTH, 0))
    TopEdge = physics.body (EDGE, vec2(0, HEIGHT-50), vec2(WIDTH, HEIGHT-50))
    LeftEdge.restitution = 1
    RightEdge.restitution = 1
    BottomEdge.restitution = 1
    TopEdge.restitution = 1

    MyBody = physics.body(CIRCLE,40) 
    MyBody.type = DYNAMIC 
    MyBody.x = WIDTH/2
    MyBody.y = 200
    MyBody.gravityScale = 0
    MyBody.restitution = 1
    MyBody.bullet = true

end

function draw()
    background(40, 40, 50)  
    strokeWidth(5) 
    fill(23, 39, 203, 255)
    MyBody.x = MyBody.x + (Gravity.x * 200)      
    MyBody.y = MyBody.y + (Gravity.y * 100)
    -- ellipse(MyBody.x, MyBody.y, 80)
    sprite("Planet Cute:Character Boy", MyBody.x, MyBody.y, 75, 75)
end

If I understand the problem correctly, you need to use a CHAIN shape. Chains ensure that the tiny “gaps” between each edge are “cemented” over.

Toadkick, I tried the CHAIN shape with the following code but the physics body goes through it at any speed. thanks.

    Borders = physics.body(CHAIN, loop, vec2( 0, 0), vec2(0, WIDTH), vec2(HEIGHT, WIDTH), vec2(HEIGHT, 0))
    Borders.type = STATIC

@DaveW: My bad, I should have examined your code a little more closely. Your problem (with the physics/collision) is that you are setting your body’s position yourself. You aren’t supposed to do that (except in special cases, like when you create the body)…that’s the physics engine’s job. Here is code that behaves more like what you were probably expecting:

-- moved out of setup per @time_trial's suggestion
displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_RIGHT)

function setup()
    LeftEdge = physics.body (EDGE, vec2(0, 0), vec2(0, HEIGHT)) 
    RightEdge = physics.body (EDGE, vec2(WIDTH, 0), vec2(WIDTH, HEIGHT))
    BottomEdge = physics.body (EDGE, vec2(0, 0), vec2(WIDTH, 0))
    TopEdge = physics.body (EDGE, vec2(0, HEIGHT-50), vec2(WIDTH, HEIGHT-50))
    LeftEdge.restitution = 1
    RightEdge.restitution = 1
    BottomEdge.restitution = 1
    TopEdge.restitution = 1

    MyBody = physics.body(CIRCLE,40) 
    MyBody.type = DYNAMIC 
    MyBody.x = WIDTH/2
    MyBody.y = 200
    --gravityScale is 1 by default. Let's leave it there
    MyBody.restitution = 1

end

function draw()
    -- this sets the physics engine's gravity every frame.
    -- we'll let the physics engine handle updating our
    -- body's position
    physics.gravity(Gravity.x * 10, Gravity.y * 10)
    background(40, 40, 50)  
    strokeWidth(5) 
    fill(23, 39, 203, 255)
    -- ellipse(MyBody.x, MyBody.y, 80)
    -- note that we are no longer setting the body's position manually
    sprite("Planet Cute:Character Boy", MyBody.x, MyBody.y, 75, 75)
end

EDIT: added @time_trial’s orientation and some comments.

I can’t help with the physics bodies, but supportedOrientations should go in the code before the setup function.

Toadkick, This seems to have fixed the problem. Very excellent!

If I have more than one physics body and want gravity to affect them differently, is there a way to do this?

Thanks much,

dave

Time_Trial,

Your suggestion is what I needed.

Thanks,

dave

@DaveW You can set the gravityScale to different values for each body. The gravity will still be towards the bottom of the screen, but at different values.

Gravity is just a constant acceleration over time. The physics engine’s “gravity” property is just a shortcut for applying a constant acceleration to each dynamic body in the simulation. If we wanted to effect different “gravities” on each body, we could turn off the physics engine’s application of gravity completely, and simply apply whatever force we want every frame to our bodies manually. Here is an example:

-- gravity demo

function setup()
    -- some control variables
    numBodies = 10
    bodyRadius = 20
    width = WIDTH
    height = HEIGHT
    
    -- turn of the physics engine's gravity altogether.
    -- we're gonna do it ourself
    physics.gravity(0, 0)
    
    -- the "ground" body
    ground = physics.body(CHAIN, true,
        vec2(0, 0),
        vec2(width, 0),
        vec2(width, height),
        vec2(0, height)
    )
    ground.type = STATIC
    
    -- we'll keep all of our bodies in this table
    bodies = {}
    
    -- create the bodies and set them up
    for i = 1, numBodies do
        -- create, setup, and add the body to our bodies table
        local body = physics.body(CIRCLE, bodyRadius)
        body.type = DYNAMIC
        body.x = math.random(bodyRadius, width - bodyRadius)
        body.y = math.random(bodyRadius, height - bodyRadius)        
        body.restitution = 0.5
        table.insert(bodies, body)        
        
        -- body.info can store a table of arbitrary values
        body.info = {}
        
        -- we'll create a random "gravity" for this body,
        -- and add it to the body's info. we'll use this
        -- again in draw()
        local dir = math.random(1, 4)
        if dir == 1 then
            -- down
            body.info.gravity = vec2(0, -10)
        elseif dir == 2 then
            -- right
            body.info.gravity = vec2(10, 0)            
        elseif dir == 3 then
            -- up
            body.info.gravity = vec2(0, 10)
        else
            -- left
            body.info.gravity = vec2(-10, 0)            
        end        
    end
end


function draw()
    background(0)
    
    -- draw the ground
    strokeWidth(2)
    stroke(255)
    line(0, 0, width, 0)
    line(width, 0, width, height)
    line(width, height, 0, height)
    line(0, height, 0, 0)
    
    -- draw the bodies
    for i, body in ipairs(bodies) do
        -- draw the body
        noStroke()    
        fill(255)        
        ellipse(body.x, body.y, bodyRadius*2)
        
        -- draw the direction that it is "facing" in green
        -- (so we can see it rolling)
        local bodyDir = vec2(1, 0):rotate(math.rad(body.angle))
        strokeWidth(2)
        stroke(0, 255, 0)
        line(body.x, body.y, body.x + bodyDir.x*10, body.y + bodyDir.y*10)
    end
    
    -- physics is updated before draw(), so let's
    -- apply "gravity" after we've drawn our bodies,
    -- since it won't be applied til next frame anyway
    for i, body in ipairs(bodies) do
        local grav = body.info.gravity
        
        -- that's right. all "gravity" really is, is a constant acceleration.
        -- i.e. a force applied constantly over time.
        body:applyForce(grav)
        
        -- draw the gravity's direction in red
        stroke(255, 0, 0)
        strokeWidth(2)
        line(body.x, body.y, body.x + grav.x*2, body.y + grav.y*2)
    end
end

Using this method opens up other possibilities too, for example radial gravity, or perhaps a simulation where every body asserts it’s gravity on every other body, or really whatever you want to do.

I did several posts on creating your own simple physics engine, see here

http://coolcodea.wordpress.com/category/physics-2/