require "physics"
function pV(x, y) return physics.Vect(x, y) end
dt = 1/32
ZERO = pV(0, 0)
LARGE = physics.misc.INFINITY()
W, H = platform.window:width(), platform.window:height()
gravity = 0
color = {0xFF00FF, 0x9900FF, 0x3399FF, 0x33CCFF, 0x00FFFF, 0x00FF33, 0xCCFF00, 0xFFFF00, 0xFFCC00, 0xFF9900, 0xFF3300, 0xFF00CC}
pBall = class()
function pBall:init(mass, radius, elasticity, friction, color, group)
self.color = color or 0
local inertia = physics.misc.momentForCircle(mass, 0, radius, ZERO)
self.body = physics.Body(mass, inertia)
self.shape = physics.CircleShape(self.body, radius, ZERO)
:setRestitution(elasticity or 0.8)
:setFriction(friction or 0.8)
if group then self.shape:setGroup(group) end
end
function pBall:paint(gc)
local cx, cy = self.body:pos():x(), self.body:pos():y()
local radius = self.shape:radius()
local diameter = radius + radius
local angle = self.body:angle()
local x0, y0 = cx - radius, cy - radius
gc:setColorRGB(self.color)
gc:fillArc(x0, y0, diameter, diameter, 0, 360)
gc:setColorRGB(0)
gc:drawArc(x0, y0, diameter, diameter, 0, 360)
gc:drawLine(cx, cy, radius * math.cos(angle) + cx, radius * math.sin(angle) + cy)
end
pBox = class()
function pBox:init(mass, width, height, elasticity, friction, color, group)
self.color = color or 0
local inertia = physics.misc.momentForBox(mass, width, height)
self.body = physics.Body(mass, inertia)
local verts = {
pV(-width/2, -height/2),
pV(-width/2, height/2),
pV( width/2, height/2),
pV( width/2, -height/2)
}
self.shape = physics.PolyShape(self.body, verts, ZERO)
:setRestitution(elasticity or 0.8)
:setFriction(friction or 0.8)
if group then self.shape:setGroup(group) end
end
function pBox:paint(gc)
local numVerts = self.shape:numVerts()
local verts = {}
for i = 1, numVerts + 1 do
local j = i; if i > numVerts then j = 1 end
table.insert(verts, self.shape:points()[j]:x())
table.insert(verts, self.shape:points()[j]:y())
end
gc:setColorRGB(self.color)
gc:fillPolygon(verts)
gc:setColorRGB(0)
gc:drawPolyLine(verts)
end
pSpace = class()
function pSpace:init(gravity)
self.space = physics.Space()
:setGravity(pV(0, gravity))
self.objects = {}
end
function pSpace:step(dt)
self.space:step(dt)
end
function pSpace:addObj(obj, velx, vely, cx, cy)
obj.body:setVel(pV(velx, vely))
:setPos(pV(cx, cy))
self.space:addBody(obj.body)
:addShape(obj.shape)
table.insert(self.objects, obj)
end
function pSpace:addStatic(obj, cx, cy)
obj.body:setPos(pV(cx, cy))
self.space:addStaticShape(obj.shape)
table.insert(self.objects, obj)
end
function pSpace:paint(gc)
for _, v in ipairs(self.objects) do
v:paint(gc)
end
gc:setPen("thin", "dotted")
gc:setColorRGB(0x8E8E38)
local sute = {}
for i = 1, #things + 1 do
local j = i; if j > #things then j = 1 end
table.insert(sute, things[j].body:pos():x())
table.insert(sute, things[j].body:pos():y())
end
gc:drawPolyLine(sute)
end
function pSpace:addConstraint(constraints)
for _, v in ipairs(constraints)
do self.space:addConstraint(v)
end
end
space = pSpace(gravity)
things = {}
for i = 1, 10 do
local sute = {
pBox(30, math.random(3, 20), math.random(3, 20), 1, 0.5, color[math.random(#color)]),
pBall(30, math.random(3, 10), 1, 0.5, color[math.random(#color)])
}
table.insert(things, sute[math.random(#sute)])
end
for _, v in ipairs(things) do
space:addObj(v, 0, 0, math.random(W/2-5,W/2+5), math.random(H/2-5,H/2+5))
end
staticBox = pBox(LARGE, 10, 10, 1, 0.8, 0xA8A8A8)
table.insert(things, staticBox)
space:addStatic(staticBox, W/2, H/2)
constraints = {}
for i = 1, #things do
local j = i + 1; if i == #things then j = 1 end;
table.insert(constraints, physics.DampedSpring(things[i].body, things[j].body, ZERO, ZERO, 70, 400, 0))
end
space:addConstraint(constraints)
function on.paint(gc)
space:paint(gc)
gc:setColorRGB(0xB5B5B5)
gc:drawString(string.format("acceleration of gravity: %d [pixels/sec"..string.uchar(0x00B2).."]", gravity), 5, 0, "top")
end
function on.timer()
space:step(dt)
platform.window:invalidate()
end
function on.enterKey()
timer.start(dt)
end