Instantly share code, notes, and snippets.

# reefwing/Main.lua Created Jul 6, 2013

Tutorial 31 - Codea Collision Detection
 --# Main -- Asteroids -- -- Simple app to demonstrate collision detection using -- the built in Box2D functionality. -- Use this function to perform your initial setup function setup() physics.gravity(0.0, 0.0) physicsDraw = PhysicsDraw() ship = createShip(WIDTH/2, HEIGHT/2) physicsDraw:addBody(ship) asteroidTimer = 1 end function createShip(x, y, w, h) -- (x, y) are the centre co-ordinates of the ship. -- (w, h) define the width and height of the box containing the ship, -- if not specified they are 50 and 35 respectively. local width = w or 50 local height = h or 35 local shipBody = physics.body(POLYGON, vec2(0, height), vec2(width, height/2), vec2(0, 0), vec2(height/2, height/2), vec2(0, height)) shipBody.x = x shipBody.y = y shipBody.type = KINEMATIC shipBody.sleepingAllowed = false shipBody.info = "ship" shipBody.interpolate = true return shipBody end function createRandPoly(x, y, s1, s2) -- s1 and s2 define the range of length for the poly sides -- count defines the number of sides of the poly local minLength = s1 or 1 local maxLength = s2 or 5 local count = math.random(5,10) local r = math.random(minLength, maxLength) 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.type = DYNAMIC poly.sleepingAllowed = false poly.restitution = 0.5 poly.info = "poly" physicsDraw:addBody(poly) return poly end function createAsteroid(x, y) return createRandPoly(x, y, 25, 65) end function placeRandomAsteroid() -- Generate (x, y) co-ordinates which are -- initially off the screen. local x = math.random(WIDTH) if x < WIDTH/2 then x = x - WIDTH else x = x + WIDTH end local y = math.random(HEIGHT) if y < HEIGHT/2 then y = y - HEIGHT else y = y + HEIGHT end -- Create an asteroid at the new co-ordinates local asteroid = createAsteroid(x, y) -- Give the asteroid a linear velocity -- towards the screen (and our ship) local dX, dY = math.random(50, 100), math.random(50, 100) if x > WIDTH then dX = -dX end if y > HEIGHT then dY = -dY end asteroid.linearVelocity = vec2(dX, dY) end function createExplosionAt(x, y) -- Creates 6 small polygon moving out from (x, y) -- to simulate our ship exploding. -- -- the body.info field is set to debris so that we -- can render it the same colour as our ship (i.e. to -- distinguish them from the asteroid polygons. randPoly1 = createRandPoly(x, y) randPoly1:applyForce(vec2(50,50)) randPoly1.info = "debris" randPoly2 = createRandPoly(x, y) randPoly2:applyForce(vec2(50,50)) randPoly2.info = "debris" randPoly3 = createRandPoly(x, y) randPoly3:applyForce(vec2(50,50)) randPoly3.info = "debris" randPoly4 = createRandPoly(x, y) randPoly4:applyForce(vec2(-50,50)) randPoly4.info = "debris" randPoly5 = createRandPoly(x, y) randPoly5:applyForce(vec2(-50,50)) randPoly5.info = "debris" randPoly6 = createRandPoly(x, y) randPoly6:applyForce(vec2(-50,50)) randPoly6.info = "debris" end -- This function gets called once every frame function draw() -- This sets a dark background color background(40, 40, 50) -- Generate a random asteroid every second asteroidTimer = asteroidTimer + DeltaTime if asteroidTimer > 1.0 then placeRandomAsteroid() asteroidTimer = 0 end -- Do your drawing here physicsDraw:draw() end -- Collision Detection -- -- This is simply a matter of checking whether one of the two -- colliding bodies are our ship. function collide(contact) if contact.bodyA == ship or contact.bodyB == ship then createExplosionAt(ship.x, ship.y) ship.info = "destroyed" ship = nil end end
 --# PhysicsDraw PhysicsDraw = class() -- Simplified Physics Debug Draw class from the Physics Lab -- example in Codea. function PhysicsDraw:init() self.bodies = {} self.contacts = {} end function PhysicsDraw:addBody(body) table.insert(self.bodies,body) end function PhysicsDraw:draw() pushStyle() smooth() noFill() for i,body in ipairs(self.bodies) do pushMatrix() translate(body.x, body.y) rotate(body.angle) if body.type == STATIC then stroke(255,255,255,255) elseif body.type == DYNAMIC and body.info ~= "debris" then stroke(150,255,150,255) else stroke(150,150,255,255) end if body.shapeType == POLYGON and body.info ~= "destroyed" 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 popMatrix() 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 PhysicsDraw: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 end end