Crates: A Physics Experiment

Well, good evening! There was another topic someone posted a while back which had a very simple example of a box, a ball and a floor. I played with it a bit (longer than I care to admit) and created some code that I think may help others to understand the physics of Codea and using sprites.

Also, I can’t help but think there are some code-saving steps I’m missing.

Enjoy, and feel free to offer any feedback!


--# Main
-- Crates
function setup()
    saveProjectInfo("Description", "An Experiment in Physics")
    supportedOrientations(LANDSCAPE_RIGHT)
    displayMode(FULLSCREEN)
    angle = 0
    spin = 0
    strokeWidth(5)
    stroke(116, 62, 39, 255)
    Objects:init()
        --This command establishes all the important information we need about our objects.
    touches = {}
    end

function drawPoly(body)
    --This is an invaluable (if not complicated-looking) function from the Physics Lab
    --example that draws the lines of a polygon on the screen. Renamed for simplicity.
    pushMatrix()
    translate(body.x, body.y)
    rotate(body.angle)
    if body.shapeType == POLYGON then
        local points = body.points
        local a, b
        for j = 1,#points do
            a = points[j]
            b = points[(j % #points)+1]
            line(a.x, a.y, b.x, b.y)
            end end
    popMatrix()
    end

function draw()
    background(40, 40, 50)
    physics.gravity(Gravity)
        --This uses the device orientation as Gravity input. This must be done in the draw()
        --function so that the orientation is re-assessed every frame.
    Objects:text()
        --Because we draw the text first, it will appear BEHIND out background image.
    sprite("Cargo Bot:Opening Crates",WIDTH/2, 296,WIDTH,296*2)
        --This doesn't serve any practical purpose aside from drawing a pretty background.
    drawPoly(walls)
        --This command draws the lines of a polygon, in this case, the walls.
    drawPoly(crate)
    drawPoly(crate2)
    drawPoly(crate3)
    drawPoly(gold)
        --These command draw the lines of the crates. Comment these out if you only
        --want to see the sprites
    Objects:draw()
        --This draws the sprites at the exact location of the polygons! Neat, huh?
    if CurrentTouch.state == BEGAN or CurrentTouch.state == MOVING then
        if CurrentTouch.x < WIDTH/2 then
            spin = 500
            gold:applyTorque(spin) end
        if CurrentTouch.x > WIDTH/2 then
            spin = -500
            gold:applyTorque(spin) end
        end
        --This bit of nonsense makes the gold crate spin in the direction of the touch.    
    end



--# Objects
Objects = class()

function Objects:init()
    --This command establishes all the important information we need about our objects.
    walls = physics.body(POLYGON, vec2(1,0), vec2(WIDTH,0), vec2(WIDTH,HEIGHT),
        vec2(0,HEIGHT), vec2(0,1), vec2(20,21), vec2(20,HEIGHT-20),
        vec2(WIDTH-20,HEIGHT-20), vec2(WIDTH-20, 20), vec2(21,20))
            --All these positions might look daunting, but dont worry: These are just
            --the points of the walls around our experiment.
    walls.type = STATIC
        --"STATIC" means "STATIONARY";They don't get to bounce around like our crate.
        
    --All of the following is information used to create our crate. Remember, this only
    --creates the "idea" of the crate. In order to see it on the screen, we need to either
    --make Codea draw the lines, or draw a sprite at the exact location of the "idea".
    --Sorry if that sounds a bit philosophical ;)
    crate = physics.body(POLYGON, vec2(0,0), vec2(100,0), vec2(100,100), vec2(0,100))
        --This creates the shape of the crate. (0,0) refers to the position of the shape,
        --not a position on the screen
    crate.type = DYNAMIC
        --This means the shape can move around, unlike our walls
    crate.x = WIDTH*.25
    crate.y = HEIGHT/2
        --The position on the screen. If this is done in draw(), the box will not be able
        --to move since you're telling Codea where to put it every frame
    crate.restitution = .6
        --How much the crate bounces... Try playing with numbers between 0 and 2.
    crate.sleepingAllowed = false
        --This command prevents objects from sleeping AKA locking in place once stopped
    crate.angle = 40
        --The angle the shape STARTS at. Again, if this is located in draw(), then you're
        --telling Codea what the angle MUST be instead of letting it change.
        
    crate2 = physics.body(POLYGON, vec2(0,0), vec2(100,0), vec2(100,100), vec2(0,100))
        --This creates a second crate with slightly different values
    crate2.type = DYNAMIC
    crate2.x = WIDTH*.5
    crate2.y = HEIGHT/2
    crate2.restitution = .7
    crate2.sleepingAllowed = false
    crate2.angle = 80
    
    crate3 = physics.body(POLYGON, vec2(0,0), vec2(100,0), vec2(100,100), vec2(0,100))
    crate3.type = DYNAMIC
    crate3.x = WIDTH*.75
    crate3.y = HEIGHT/2
    crate3.restitution = .8
    crate3.sleepingAllowed = false
    crate3.angle = 15
    
    gold = physics.body(POLYGON, vec2(0,0), vec2(100,0), vec2(100,100), vec2(0,100))
    gold.type = DYNAMIC
    gold.x = WIDTH*.5
    gold.y = HEIGHT/4
    gold.restitution = .5
    gold.sleepingAllowed = false
end

function Objects:draw()
    pushMatrix()
        --The rotating of the crate image must be done in a "matrix", otherwise the
        --rotation command will turn everything on the screen!
    translate(crate.x, crate.y)
        --"translate" reorients the position of (0,0). In this case, the position of the
        --crate is now (0,0), no matter where on the screen it appears!
    rotate(crate.angle)
        --So long as the sprite and the polygon rotate at exactly the same angle, they
        --will overlap exactly.
    sprite("Cargo Bot:Title Large Crate 1", 50,50, 100, 100)
        --Since (0,0) was reset to the polygon's exact position, we need to make sure that
        --the sprite corresponds to the "new" (0,0)
    popMatrix()
    
    pushMatrix()
        --This will draw a sprite for our second crate
    translate(crate2.x, crate2.y)
    rotate(crate2.angle)
    sprite("Cargo Bot:Title Large Crate 2", 50,50, 100, 100)
    popMatrix()
    
    pushMatrix()
    translate(crate3.x, crate3.y)
    rotate(crate3.angle)
    sprite("Cargo Bot:Title Large Crate 3", 50,50, 100, 100)
    popMatrix()
    
    pushMatrix()
    translate(gold.x, gold.y)
    rotate(gold.angle)
    sprite("Cargo Bot:Crate Yellow 2", 50,50, 100, 100)
    popMatrix()
    end
    
function Objects:text()
    pushMatrix()
    angle = angle + .5
    if angle > 360 then angle = 0 end
    translate(WIDTH/2,HEIGHT/2)
    rotate(angle)
    fontSize(70)
    font("HoeflerText-Black")
    fill(116, 62, 39, 255)
    text("Bounce The Crates!",0,0)
    popMatrix()
    end

Thanks! many things got more clear now, great boost for a starter.