Skip to content

Instantly share code, notes, and snippets.

@juaxix
Created July 21, 2012 13:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juaxix/3155875 to your computer and use it in GitHub Desktop.
Save juaxix/3155875 to your computer and use it in GitHub Desktop.
2D physic puzzle / sandbox game made in Codea
Car = class()
-- 2D Physics game made in Codea by @juaxix
-- More games: xixgames.com
-- 21/07/2012
-- inspired by Codea Physics tutorial and Crayon Physics :)
function Car:init(x,y) 
    local car = physics.body(POLYGON, vec2(-50,10), vec2(-50,-10), vec2(50,-10), vec2(50,10), vec2(30,10),vec2(25,25),vec2(-25,25),vec2(-30,10))
    car.position = vec2(x, y)
    debugDraw:addBody(car)
    car.density = 2.0
    
    local piston = physics
    
    local leftPos = vec2(x - 30, y-10)
    local leftWheel = createCircle(leftPos.x, leftPos.y, 20) 
    leftWheel.friction = 1  
    self.leftJoint = physics.joint(REVOLUTE, car, leftWheel, leftWheel.position)
    self.leftJoint.maxMotorTorque = 10
    
    local rightPos = vec2(x + 30, y-10)
    local rightWheel = createCircle(rightPos.x, rightPos.y, 15)    
    rightWheel.friction = 1
    self.rightJoint = physics.joint(REVOLUTE, car, rightWheel, rightWheel.position)
    
    
end
function Car:cleanup()
    self.leftJoint = nil
    self.rightJoint = nil
end
function Car:touched(touch)
    -- Codea does not automatically call this method
    if touch.state == BEGAN or touch.state == MOVING then
        self.leftJoint.enableMotor = true
        if touch.x > WIDTH/2 then
            self.leftJoint.motorSpeed = -1666
        else
            self.leftJoint.motorSpeed = 3333
        end
    elseif touch.state == ENDED then
        self.leftJoint.motorSpeed = 0
    end
end
-- Firework Class
-- 2D Physics game made in Codea by @juaxix
-- More games: xixgames.com
-- 21/07/2012
-- inspired by Codea Physics tutorial and Crayon Physics :)
Firework_Parts = 33
Life = 11
Life_Variation = 100
Air_Resistance = 0.1
PartSize = 60
PartSize_Variation = 166
Velocity = 6
Velocity_Variation = 11
Color_Variation = 50
Firework = class()
function Firework:init(position)
    -- you can accept and set parameters here
    self.p = {}
    self.position = position
    local colour = color(243, 255, 0, 255)
    self.numParticles = Firework_Parts
    for i=1,self.numParticles do
        local psize = genNumber(PartSize,PartSize_Variation)
        
        local v = vec2(math.random(-100,100),math.random(-100,100))
        v = v:normalize()
        v = v * genNumber(Velocity,Velocity_Variation)
        
        --[[local c = color(genNumber(colour.r,Color_Variation),
                        genNumber(colour.g,Color_Variation),
                        genNumber(colour.b,Color_Variation),
                        colour.a
                        )]]--
        
        self.p[i] = Particle(
        --posx,posy,size,life,colour, velocity,mass,angle,sprite)
                        position.x,
                        position.y,
                       130,
                        genNumber(Life,Life_Variation),
                        color(255, 255, 255, 255),
                        v,
                        1,
                        0,
                        "SpaceCute:Star")
    end
end
function Firework:draw()
    local resistance = 1/(Air_Resistance + 1)
    --local g = vec2(Gravity.x,Gravity.y)
    local g = vec2(0.040731, 0.1)
    for i=1,self.numParticles do
        local p = self.p[i]
        
        p.x = p.x + p.v.x
        p.y = p.y + p.v.y
        
        p.v = p.v + g
        p.v = p.v * resistance
        
        local size = math.random(PartSize) * (p.lifeLeft/p.life)
        p.width = size
        p.height = size
        p:draw()
    end
end
function Firework:isDead()
    for i=1,self.numParticles do
        p = self.p[i]
        if p.lifeLeft ~= 0 and
            (p.x>0 and p.x<WIDTH and p.y>0 and p.y<HEIGHT)then
            return false
        end
    end
    return true
end
Particle = class()
Particle.DEFAULT_OPACITY = 125
Particle.DEFAULT_ANGLE = 0
Particle.DEFAULT_MASS = 1
function Particle:init(posx,posy,size,life,colour,
    velocity,mass,angle,sprite)
    -- position
    self.x = posx
    self.y = posy
    self.ox = 0
    self.oy = 0
    
    -- size
    self.width = size
    self.height = size
    
    -- color
    if colour == nil then
        self.color = color(255, 255, 255, 255)
    else
        self.color = colour
    end
    
    -- velocity
    self.v = velocity
    
    -- life
    self.life = life
    self.lifeLeft= life
    
    -- sprite
    self.sprite = sprite
    
    -- mass
    if mass == nil then
        self.mass = DEFAULT_MASS
    else
        self.mass = mass
    end
    
    -- angle
    if angle == nil then
        self.angle = self.DEFAULT_ANGLE
    else
        self.angle = angle
    end
end
function Particle:draw()
    if self.lifeLeft > 0 then
        self.lifeLeft = self.lifeLeft - 1
    end
    
    if self.lifeLeft ~= 0 then
        if self.sprite == nil then
            fill(self.color)
            ellipse(self.x,self.y,self.width,self.height)
        else
            pushMatrix()
            translate(self.x,self.y)
            rotate(self.angle)
            tint(self.color)
            sprite(self.sprite,0,0,self.width,self.height)
            popMatrix()
        end
    end
end
function genNumber(number,variation)
    ret = variation*0.01*number
    ret = number + math.random(-ret,ret)
    return ret
end
Smoke = class()
function Smoke:init(x,y,n)
    self.numparts = n
    -- color used to tint the particle
    local c = color(73, 73, 73, 69)
    -- name of the sprite of each smoke particle
    local s = "Tyrian Remastered:Dark Orb"
    
    self.parts = {}
    for i=0,n do
        -- initial size of the smoke particle
        local sz = genNumber(60,100)
        self.parts[i] = Particle(genNumber(x,20),
                            genNumber(y,20),sz,-7,c,nil,-1,genNumber(180,100),s)
    end
    -- rotation speed
    self.rSpeed = 0.5
    self.windX = 1
    self.windY = 1
end
function Smoke:draw()
    for i=1,self.numparts do
        local p = self.parts[i]
        if p.color.a > 0 then
        p.angle = p.angle + self.rSpeed
        p.width = p.width + 3
        p.height = p.height + 3
        p.color.a = p.color.a - 0.2
        p.x = p.x + self.windX
        p.y = p.y + self.windY
        p:draw()
        end
    end
end
function Smoke:isDead()
    for i=1,self.numparts do
        local p = self.parts[i]
        if p.color.a > 0 then
            return false
        end
    end
    return true
end
-- Level Class
Level = class()
-- 2D Physics game made in Codea by @juaxix
-- More games: xixgames.com
-- 21/07/2012
-- inspired by Codea Physics tutorial and Crayon Physics :)
current_level = 1
winner = false
loser  = false
levels = { -- levels
  { -- level 1
    { -- ground body list
     type = POLYGON,v1=vec2(0,20),v2=vec2(0,0),v3=vec2(WIDTH,0), v4=vec2(WIDTH,20),
     ball = vec2(166,110), star = vec2(WIDTH - 60, 110)
    },{ -- left wall
     type = POLYGON,v1=vec2(0,HEIGHT),v2=vec2(0,0),v3=vec2(-2,0), v4=vec2(-2,HEIGHT)
    } ,{ -- right wall
     type = POLYGON,v1=vec2(WIDTH+1,HEIGHT),v2=vec2(WIDTH+1,0), v3=vec2(WIDTH,0), 
                     v4=vec2(WIDTH,HEIGHT)
    }
  },
  {-- level 2
    {-- first platform
     type = POLYGON,v1=vec2(WIDTH/2,HEIGHT/3),v2=vec2(WIDTH/2,(HEIGHT/3)-11),
                    v3=vec2((WIDTH/3),(HEIGHT/3)-11), v4=vec2(WIDTH/3,(HEIGHT/3)),
                    ball = vec2(WIDTH/2 - 33,HEIGHT/3), star = vec2(WIDTH / 1.3, HEIGHT/4),
                    
    },
    { -- second platform
    type = POLYGON,v1=vec2(WIDTH/1.1,HEIGHT/5),v2=vec2(WIDTH/1.1,(HEIGHT/5)-11),
                    v3=vec2((WIDTH/1.6),(HEIGHT/5)-11), v4=vec2(WIDTH/1.6,(HEIGHT/5)),
    }
  } , { -- level 3
    { -- ground body list
     type = POLYGON,v1=vec2(0,20),v2=vec2(0,0),v3=vec2(WIDTH,0), v4=vec2(WIDTH,20),
     ball = vec2(166,110), star = vec2(WIDTH - 60, 110), car = vec2(60,50)
    },{ -- left wall
     type = POLYGON,v1=vec2(0,HEIGHT),v2=vec2(0,0),v3=vec2(-2,0), v4=vec2(-2,HEIGHT)
    } ,{ -- right wall
     type = POLYGON,v1=vec2(WIDTH+1,HEIGHT),v2=vec2(WIDTH+1,0), v3=vec2(WIDTH,0), 
                    v4=vec2(WIDTH,HEIGHT)
    }, { -- obstacle
      type = POLYGON,v1=vec2(WIDTH/1.5,66),v2=vec2(WIDTH/1.5,20),v3=vec2(WIDTH/2,20), 
                     v4=vec2(WIDTH/2,66)
    }
  },{ -- level 
    { -- ground body list
     type = POLYGON,v1=vec2(0,0),v2=vec2(0,10),v3=vec2(WIDTH,10), v4=vec2(WIDTH,0),
     ball = vec2(66,HEIGHT), star = vec2(WIDTH - 60, HEIGHT), spring = true,
    -- star platform
    --v1=vec2(WIDTH-111,166),v2=vec2(WIDTH-111,120),v3=vec2(WIDTH-33,120), 
                  --   v4=vec2(WIDTH-33,166)
     door = {v1=WIDTH-66,v2=111,v3=33,v4=46}
    },
     { -- ball platform
      type = POLYGON,v1=vec2(33,166),v2=vec2(33,120),v3=vec2(120,120), 
                     v4=vec2(120,166)
    },{ -- right wall
     type = POLYGON,v1=vec2(WIDTH+1,HEIGHT/2),v2=vec2(WIDTH+1,0), v3=vec2(WIDTH,-6), 
                    v4=vec2(WIDTH,HEIGHT/2)
    }, { -- obstacle
    type = POLYGON,v1=vec2(WIDTH/1.3-11,66),v2=vec2(WIDTH/1.3-11,20),v3=vec2(WIDTH/1.2-11,20), 
                     v4=vec2(WIDTH/1.2-11,66)
    }
  }
}
function Level:init()
    self.car = nil
    self.spring = nil
    self:load(current_level)
end
function Level:load(levelnum)
    if levelnum > #levels then levelnum = 1 end
    self.car = nil
    self.spring = nil
    for i,l in ipairs(levels[levelnum]) do
        local ground = physics.body(l.type, l.v1, l.v2,l.v3,l.v4)
        ground.type = STATIC
        debugDraw:addBody(ground)
        ground.friction = 1
    end
    -- create game elements
    self.ball = createCircle( levels[levelnum][1].ball.x,levels[levelnum][1].ball.y ,30)
    self.star = createCircle( levels[levelnum][1].star.x,levels[levelnum][1].star.y, 30)
    if levels[levelnum][1].car~=nil then
        self.car = Car(levels[levelnum][1].car.x, levels[levelnum][1].car.y)
    end
    if levels[levelnum][1].spring~=nil then
        self.spring = Spring(self.ground)
        if levels[levelnum][1].door then
            self.spring.door = createBox(
                levels[levelnum][1].door.v1,
                levels[levelnum][1].door.v2,
                levels[levelnum][1].door.v3,
                levels[levelnum][1].door.v4
            )
            self.spring.door.type = STATIC
            debugDraw:addBody(self.spring.door)
            self.spring.door.friction = 1
        end
    end
    self.time = os.clock()
end
function Level:createFirework(pos)
    self.stars= Firework(vec2(self.star.x,self.star.y))
end
function Level:draw()
    if self.stars then
        self.stars:draw()
        if self.stars:isDead() then
            self.stars:init(self.stars.position)
        end
    end
    if self.spring ~= nil then 
        self.spring:draw()
    end
    noTint()
    pushMatrix()
    translate(self.ball.x,self.ball.y)
    rotate(self.ball.angle)
    sprite("Tyrian Remastered:Dark Orb", 0,0,60)
    popMatrix()
    pushMatrix()
    translate(self.star.x, self.star.y)
    rotate(self.star.angle)
    sprite("SpaceCute:Star")
    popMatrix()
end
function Level:touched(touch)
    --createRandPoly(touch.x, touch.y)
    if self.car ~= nil then
        self.car:touched(touch)
    end
end
-- Main program
-- 2D Physics game made in Codea by @juaxix
-- More games: xixgames.com
-- 21/07/2012
-- inspired by Codea Physics tutorial and Crayon Physics :)
tt = nil
last_touch = nil
touch = nil
moving = false
dd = false
MODE_DRAW = 1
MODE_MOVE = 2
Mode = MODE_MOVE
timer = 0
time  = 0
level = nil
-- Use this function to perform your initial setup
function setup()
    tt = Touches()
    supportedOrientations(LANDSCAPE_ANY)
    lineCapMode(PROJECT)
    debugDraw = PhysicsDebugDraw()
    defaultGravity = physics.gravity()
    level = Level()
    tint(255, 0, 0, 255)
    iparameter("Mode",MODE_DRAW,MODE_MOVE,MODE_MOVE)
    backingMode(RETAINED)
end
-- This function gets called once every frame
function draw()
    background(0, 0, 0, 0)
    if not winner and not loser then
        drawGame()
    elseif loser then
        font("Copperplate")
        fontSize(66)
        fill(240, 47, 47, 255)
        text("Try Again", WIDTH/2,HEIGHT/2)
        fontSize(23)
        --text(time.." s", (WIDTH/2),(HEIGHT/2)-33)
        timer = timer - 1
        if timer <= 0 then
            timer = 0
            debugDraw:clear()
            level:load(current_level)
            loser = false
        end
    else
        font("Arial-BoldMT")
        fontSize(66)
        fill(255)
        text("Well done!", WIDTH/2,HEIGHT/2)
        fontSize(23)
        text(time.." s", (WIDTH/2),(HEIGHT/2)-33)
        timer = timer - 1
        if timer <= 0 then
            timer = 0
            debugDraw:clear()
            current_level = current_level + 1
            level:load(current_level)
            winner = false
        end
    end
end
function drawGame()
    if Mode == MODE_DRAW then
     if (#debugDraw.bodies<60) then 
        touch = vec2(CurrentTouch.x, CurrentTouch.y)
        if CurrentTouch.state == ENDED then
            -- to make sure we don't miss the touch began state
            
        elseif CurrentTouch.state == BEGAN then
            if touch ~= last_touch then
                moving = true
                last_touch = touch
                tt:add(touch)
            end
        elseif CurrentTouch.state == MOVING then
            if touch ~= last_touch then
                if moving then
                    tt:expand(touch)
                else
                    -- Did not detect the move
                    moving = true
                    tt:add(touch)
                end
                last_touch = touch
            end       
        end
     end
    end
    debugDraw:draw()
    if use_accelerometer == 1 then
        physics.gravity(Gravity)
    else
        physics.gravity(defaultGravity)
    end
    level:draw()
    tt:draw()
    
end
function createCircle(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
    debugDraw:addBody(circle)
    return circle
end
function createBox(x,y,w,h)
    -- polygons are defined by a series of points in counter-clockwise order
    local box = physics.body(POLYGON, vec2(-w/2,h/2), vec2(-w/2,-h/2), vec2(w/2,-h/2), vec2(w/2,h/2))
    box.interpolate = true
    box.x = x
    box.y = y
    box.restitutions = 0.25
    box.sleepingAllowed = false
    debugDraw:addBody(box)
    return box
end
function createGround()
    local ground = physics.body(POLYGON, vec2(0,20), vec2(0,0), vec2(WIDTH,0), vec2(WIDTH,20))
    ground.type = STATIC
    debugDraw:addBody(ground)
    return ground
end
function createRandPoly(x,y)
    if (#debugDraw.bodies>60) then return end
    local count = math.random(3,10)
    local r = math.random(25,75)
    local a = 0
    local d = 2 * math.pi / count
    local points = {}
    
    for i = 1,count do
        local v = vec2(r,0):rotate(a) + vec2(math.random(-10,10), math.random(-10,10))
        a = a + d
        table.insert(points, v)
    end
    
    
    local poly = physics.body(POLYGON, unpack(points))
    
    poly.x = x
    poly.y = y
    poly.sleepingAllowed = false
    poly.restitution = 0.25
    debugDraw:addBody(poly)
    return poly
end
function cleanup()
    clearOutput()
    debugDraw:clear()
end
function collide(contact)
    debugDraw:collide(contact)
    if level.collide then
        level:collide(contact)
    end
end
function createTouchedPolygon(x,y)
    if (#debugDraw.bodies>60) then return end
    local count = #tt.touches
    if count == 0 then return nil end
    local r = math.random(25,75)
    local a = 0
    local d = 2 * math.pi / count
    local points = {}
    
    --[[for i = 1,count do
        local v = vec2(r,0):rotate(a) + vec2(math.random(-10,10), math.random(-10,10))
        a = a + d
        table.insert(points, v)
    end]]--
    
    for i,w in ipairs(tt.touches) do
        for j,v in ipairs(w) do
            table.insert(points, vec2(v.x,v.y))
        end
    end
   
    
    local poly = physics.body(POLYGON, unpack(points))
    if poly == nil then return createRandPoly(x,y) end
    --print(poly.mass)
    poly.x = 0
    poly.y = 0
    poly.sleepingAllowed = true
    poly.restitution = 0.25/(#points/3)
    --poly.mass = #points
    debugDraw:addBody(poly)
    mesh()
    return poly
end
function touched(touch)
    if Mode == MODE_MOVE then
     if debugDraw:touched(touch) then 
        tt.touches = {}
        moving = false
     end  
     level:touched(touch)
    elseif Mode == MODE_DRAW then
     if touch.state == ENDED then
        moving = false
        if #tt.touches>0 and #tt.touches[1]>1 then
            createTouchedPolygon(touch.x,touch.y)
        else
            createRandPoly(touch.x, touch.y)
        end
        tt.touches = {}
        
        
     end
    end
end
-- PhysicsDebugDraw class
PhysicsDebugDraw = class()
-- 2D Physics game made in Codea by @juaxix
-- More games: xixgames.com
-- 21/07/2012
-- inspired by Codea Physics tutorial and Crayon Physics :)
function PhysicsDebugDraw:init()
    self.bodies = {}
    self.joints = {}
    self.touchMap = {}
    self.contacts = {}
end
function PhysicsDebugDraw:addBody(body)
    table.insert(self.bodies,body)
end
function PhysicsDebugDraw:addJoint(joint)
    table.insert(self.joints,joint)
end
function PhysicsDebugDraw:clear()
    -- deactivate all bodies
    
    for i,body in ipairs(self.bodies) do
        body:destroy()
    end
  
    for i,joint in ipairs(self.joints) do
        joint:destroy()
    end      
    
    self.bodies = {}
    self.joints = {}
    self.contacts = {}
    self.touchMap = {}
end
function PhysicsDebugDraw:draw()
    
    pushStyle()
    smooth()
    strokeWidth(5)
    stroke(128,0,128)
    noFill()
    local gain = 2.0
    local damp = 0.5
    for k,v in pairs(self.touchMap) do
        if v.body == nil or v.body.x == nil then
            table.remove(self.touchMap, k)
        else
            local worldAnchor = v.body:getWorldPoint(v.anchor)
            local touchPoint = v.tp
            local diff = touchPoint - worldAnchor
            local vel = v.body:getLinearVelocityFromWorldPoint(worldAnchor)
            v.body:applyForce( (1/1) * diff * gain - vel * damp, worldAnchor)
            
            line(touchPoint.x, touchPoint.y, worldAnchor.x, worldAnchor.y)
        end
    end
    
    stroke(0,255,0,255)
    strokeWidth(5)
    for k,joint in pairs(self.joints) do
        local a = joint.anchorA
        local b = joint.anchorB
        line(a.x,a.y,b.x,b.y)
    end
    stroke(255,255,255,255)
    for i,body in ipairs(self.bodies) do
     if body==nil or body.x==nil then
        table.remove(self.bodies,i)
     elseif body ~= level.ball and level.star ~= body then 
        pushMatrix()
        translate(body.x, body.y)
        rotate(body.angle)
    
        if body.type == STATIC then
            stroke(255,255,255,255)
        elseif body.type == DYNAMIC then
            --stroke(150,255,150,255)
            stroke(255)
        elseif body.type == KINEMATIC then
            stroke(150,150,255,255)
        end
    
        if body.shapeType == POLYGON then
            strokeWidth(5.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(5.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(5.0)
            line(0,0,body.radius-3,0)
            strokeWidth(2.5)
            noFill()
            ellipse(0,0,body.radius*2)
        end
        
        popMatrix()
        if math.abs(body.x) > WIDTH*2 or  body.y <-HEIGHT*2 then
            --print(body.x..","..body.y)
            body:destroy()
            table.remove(self.bodies, i)
            print("removing "..i)
        end
     elseif body == level.ball then
        if body.x > WIDTH+10 or body.x < -10 or body.y <-10 then
            loser = true
            timer = 66
        end
     end
    end 
    
    stroke(255, 0, 0, 255)
    fill(255, 0, 0, 255)
    for k,v in pairs(self.contacts) do
        for m,n in ipairs(v.points) do
            ellipse(n.x, n.y, 10, 10)
        end
    end
    
    popStyle()
   
end
function PhysicsDebugDraw:touched(touch)
    local touchPoint = vec2(touch.x, touch.y)
    if touch.state == BEGAN then
        for i,body in ipairs(self.bodies) do
            if body.type == DYNAMIC and body:testPoint(touchPoint) then
                if body == level.star or body == level.ball then
                    
                else
                 self.touchMap[touch.id] = {
                    tp = touchPoint, 
                    body = body, 
                    anchor = body:getLocalPoint(touchPoint)
                    } 
                    if self.singleTouch == i then
                        self.doubleTouch = i
                    else
                        self.singleTouch = i
                        self.doubleTouch = nil
                    end
                end
                return true
            end
        end
    elseif touch.state == MOVING and self.touchMap[touch.id] then
        self.touchMap[touch.id].tp = touchPoint
        self.singleTouch = nil
        self.doubleTouch = nil
        return true
    elseif touch.state == ENDED and self.touchMap[touch.id] then
        self.touchMap[touch.id] = nil
        if self.singleTouch~=nil and self.singleTouch == self.doubleTouch then
            -- remove body
            self.bodies[self.singleTouch]:destroy()
            table.remove(self.bodies, self.singleTouch)
            self.singleTouch = nil
            self.doubleTouch = nil
        else
            
        end
        return true
    end
    return false
end
function PhysicsDebugDraw:collide(contact)
    if contact.state == BEGAN then
        self.contacts[contact.id] = contact
        sound(SOUND_HIT, 2643)
    elseif contact.state == MOVING then
        self.contacts[contact.id] = contact
    elseif contact.state == ENDED then
        self.contacts[contact.id] = nil
        if (contact.bodyA == level.star or contact.bodyB == level.star) then
            if level.star.type ~= STATIC and 
             (contact.bodyA == level.star or 
              contact.bodyB == level.star) 
            then
              level.star.type = STATIC
              level:createFirework(vec2(level.star.x, level.star.y))
            end
        end
        if (contact.bodyA == level.star and contact.bodyB == level.ball) or
           (contact.bodyB == level.star and contact.bodyA == level.ball) then
            winner = true
            timer  = 66
            time   = os.clock() - level.time 
        end
    end
    
end
-- Spring class
Spring = class()
-- 2D Physics game made in Codea by @juaxix
-- More games: xixgames.com
-- 21/07/2012
-- inspired by Codea Physics tutorial and Crayon Physics :)
function Spring:init()
    self.point1 = vec2(WIDTH/2, 0)
    self.point2 = vec2(WIDTH/2, HEIGHT/4)
    self.point3 = vec2(0, 30)
    self.point4 = vec2(WIDTH/3, 30) 
    self.aabb = {vec2(WIDTH/2 -11,HEIGHT/2), vec2(WIDTH/2 +11,HEIGHT/2 - 10)}
end
function Spring:draw()
    result = physics.raycast(self.point1, self.point2)
    pushStyle()
    stroke(0, 255, 0, 255)
    strokeWidth(5)
    if result then    
        line(self.point1.x, self.point1.y, result.point.x, result.point.y)
        result.body:applyForce(vec2(0,66))
    else
        line(self.point1.x, self.point1.y, self.point2.x, self.point2.y)
    end
    
    line(self.point3.x, self.point3.y, self.point4.x, self.point4.y)
    
    fill(255, 0, 0, 255)
    results = physics.raycastAll(self.point3, self.point4)
    for k,v in ipairs(results) do
        ellipse(v.point.x, v.point.y, 10, 10)
        v.body:applyForce(vec2(23,0))
    end
        
    strokeWidth(5)
    noFill()
    local activators = physics.queryAABB(self.aabb[1], self.aabb[2])
    if self.door~= nil and #activators > 0 then
        stroke(255, 0, 255, 255)
        -- open door
        for i,a in ipairs(activators) do
            if a == level.ball then
                self.door:destroy()
                level.star.type = DYNAMIC
                self.door = nil
                break
            end
        end
    else
        stroke(194, 194, 194, 128)
    end
    rectMode(CORNERS)
    rect(self.aabb[1].x, self.aabb[1].y, self.aabb[2].x, self.aabb[2].y)
    
    popStyle()
    
end
function Spring:cleanup()
end
function Spring:touched(touch)
end
-- Touches class
Touches = class()
-- 2D Physics game made in Codea by @juaxix
-- More games: xixgames.com
-- 21/07/2012
-- inspired by Codea Physics tutorial and Crayon Physics :)
function Touches:init()
    self.touches = {}
end
function Touches:add(t)
    table.insert(self.touches, {t})
end
function Touches:expand(t)
    table.insert(self.touches[#self.touches],t)
end
function Touches:draw()
    local last
    strokeWidth(5)
    if #self.touches > 0 then
        for i,v in ipairs(self.touches) do
            last = v[1]
            stroke(255, 255, 255, 255)
            for j,w in ipairs(v) do
                line(last.x,last.y,w.x,w.y)
                last = w
            end
        end
    end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment