Created
July 6, 2013 04:55
-
-
Save reefwing/5938689 to your computer and use it in GitHub Desktop.
Tutorial 31 - Codea Collision Detection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--# 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