Skip to content

Instantly share code, notes, and snippets.

@reefwing
Created July 6, 2013 04:55
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 reefwing/5938689 to your computer and use it in GitHub Desktop.
Save reefwing/5938689 to your computer and use it in GitHub Desktop.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment