Skip to content

Instantly share code, notes, and snippets.

@reefwing
Created July 31, 2012 11:05
Show Gist options
  • Save reefwing/3216208 to your computer and use it in GitHub Desktop.
Save reefwing/3216208 to your computer and use it in GitHub Desktop.
Tutorial 11 - Physics 101
supportedOrientations(ANY)
function setup()
-- Physics Demo Metadata
version = 1.0
saveProjectInfo("Description", "Physics v"..version)
saveProjectInfo("Author", "Reefwing Software")
saveProjectInfo("Date", "30th July 2012")
saveProjectInfo("Version", version)
print("Physics Demo v"..version.."\n")
-- Load the sprite you want to attach to your physics object
-- you want the sprite and the object to be roughly the same
-- size and shape.
img = readImage("Dropbox:Mine_64x64")
-- Create an instance of PhysicsDebugDraw(). You will need to copy
-- this tab from the Physics Lab project or duplicate the project
-- and make it a dependency to your project. We have modified the
-- code to allow you to make the ground invisible and attach a
-- sprite. A copy of the modified class is provided below.
physicsDraw = PhysicsDebugDraw()
physicsDraw.spriteImage = img
physicsDraw.staticVisible = false
-- These functions are from the Physics Lab example which we have
-- extracted and provided in the Physics file below. As our sprite
-- is circular we attach it to the circle sprite.
createGround()
createBox(WIDTH/2, 100, 30, 30)
createCircle(WIDTH/2 + 50, HEIGHT, 32)
createRandPoly(WIDTH/2 + 150, 120)
end
function draw()
-- This sets the background color to black
background(blackColor)
-- Draw Demo Physics objects
physicsDraw:draw()
end
function collide(contact)
-- Leave this function out if you don't want to show the red dots
-- which indicate the collision points.
physicsDraw:collide(contact)
end
function touched(touch)
-- Use this method to demonstrate the pointInRect() collision detection function
if touch.state == ENDED then
-- Create a random polygon wherever you tap the screen.
createRandPoly(touch.x, touch.y, 25, 25)
end
end
--# Physics
--
-- Functions from the Physics Lab example project
-- courtesy of Two Lives Left
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
physicsDraw: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
physicsDraw: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
physicsDraw:addBody(ground)
return ground
end
function createRandPoly(x,y)
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
physicsDraw:addBody(poly)
return poly
end
function cleanup()
clearOutput()
physicsDraw:clear()
end
--# PhysicsDebugDraw
--
-- Class extracted from the Physics Lab project.
-- courtesy of Two Lives Left
--
-- Modified by Reefwing Software
-- Version 1.0
PhysicsDebugDraw = class()
function PhysicsDebugDraw:init()
self.bodies = {}
self.joints = {}
self.touchMap = {}
self.contacts = {}
self.spriteImage = nil -- spriteImage parameter added
self.staticVisible = true -- used to make ground invisible if required.
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)
local gain = 2.0
local damp = 0.5
for k,v in pairs(self.touchMap) do
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
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)
noFill()
for i,body in ipairs(self.bodies) do
pushMatrix()
translate(body.x, body.y)
rotate(body.angle)
if body.type == STATIC then
if self.staticVisible then
stroke(255,255,255,255)
else
stroke(0,0,0,0)
end
elseif body.type == DYNAMIC then
stroke(150,255,150,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
if self.spriteImage == nil then
strokeWidth(5.0)
line(0,0,body.radius-3,0)
strokeWidth(2.5)
ellipse(0,0,body.radius*2)
else
sprite(self.spriteImage, 0, 0, body.radius*2)
end
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 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
self.touchMap[touch.id] = {tp = touchPoint, body = body, anchor = body:getLocalPoint(touchPoint)}
return true
end
end
elseif touch.state == MOVING and self.touchMap[touch.id] then
self.touchMap[touch.id].tp = touchPoint
return true
elseif touch.state == ENDED and self.touchMap[touch.id] then
self.touchMap[touch.id] = nil
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
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment