Skip to content

Instantly share code, notes, and snippets.

@gaspard
Created January 18, 2012 21:54
Show Gist options
  • Save gaspard/1636042 to your computer and use it in GitHub Desktop.
Save gaspard/1636042 to your computer and use it in GitHub Desktop.
Simple Box2D demo with Lubyk
require 'lubyk'
-- Box2D bindings are not yet in published but code will look the same
-- (18.1.2012)
local function makeBody(x, y, r, hue)
-- Define the dynamic body. We set its position and call the body factory.
local bodyDef = b2.BodyDef()
bodyDef.type = b2.dynamicBody
bodyDef.position:Set(x, y)
local body = world:CreateBody(bodyDef)
-- Create a shape
local shape = b2.CircleShape()
-- Position in body
shape.m_p:Set(0, 0);
-- Size
shape.m_radius = r;
-- Define the dynamic body fixture.
local fixtureDef = b2.FixtureDef()
fixtureDef.shape = shape
-- Set the box density to be non-zero, so it will be dynamic.
fixtureDef.density = 1.0
-- Override the default friction.
fixtureDef.friction = 0.3
-- Make it bump
fixtureDef.restitution = 0.5
-- Add the shape to the body.
body:CreateFixture(fixtureDef)
return {
body = body,
type = 'Circle',
radius = r,
pen = mimas.Pen(1, mimas.Color(hue, 0.8, 0.8, 0.8)),
brush = mimas.Brush(mimas.Color(hue, 0.5, 0.5, 0.5)),
}
end
run(function()
-- Define the gravity vector.
local gravity = b2.Vec2(0.0, -10.0)
-- Construct a world object, which will hold and simulate the rigid bodies.
world = b2.World(gravity)
-- Define the ground body.
local groundBodyDef = b2.BodyDef()
groundBodyDef.position:Set(10, 5)
-- Call the body factory which allocates memory for the ground body
-- from a pool and creates the ground box shape (also from a pool).
-- The body is also added to the world.
local groundBody = world:CreateBody(groundBodyDef)
local WORLD_SIZE = {w = 20, h = 20}
bodies = {}
-- Create some circles
for i=1,20 do
local x, y, r = math.random() * WORLD_SIZE.w, math.random() * WORLD_SIZE.h, math.random() * 1.5
table.insert(bodies, makeBody(x, y, r, math.random()))
end
-- Define the ground box shape.
local groundBox = b2.PolygonShape()
-- The extents are the half-widths of the box.
groundBox:SetAsBox(5.0, 1.0)
-- Add the ground fixture to the ground body.
groundBody:CreateFixture(groundBox, 0.0)
table.insert(bodies, {
body = groundBody,
type = 'Box',
-- half width
w = 5,
-- half height
h = 1,
pen = mimas.Pen(1, mimas.Color(0, 0, 0.8, 0.8)),
brush = mimas.Brush(mimas.Color(0, 0, 0.5, 0.5)),
})
-- Prepare for simulation. Typically we use a time step of 1/60 of a
-- second (60Hz). This provides a high quality simulation
-- in most game scenarios.
local timeStep = 1.0 / 60.0
local velocityIterations = 6
local positionIterations = 2
local win = mimas.Window()
win:resize(500, 500)
win:show()
sleep(1000)
local OFFSET_X = 50
local scale = win:width() / WORLD_SIZE.w -- 200 px / 10 meters
local function drawElement(elem, p, w, h)
p:setPen(elem.pen)
p:setBrush(elem.brush)
local position = elem.body:GetPosition()
local x, y = OFFSET_X + position.x * scale, h - position.y * scale
-- If the body falls off, we remove it
if y > h + 150 then
return false
end
if elem.type == 'Circle' then
local r = elem.radius * scale
p:drawEllipse(x-r, y-r, 2*r, 2*r)
elseif elem.type == 'Box' then
local w, h = elem.w * scale, elem.h * scale
p:drawRect(x - w, y - h, 2*w, 2*h)
end
return true
end
local last_x, last_y = 0, 0
function win:mouse(x, y)
if math.abs(last_x - x) + math.abs(last_y - y) > 10 then
last_x = x
last_y = y
-- create a new body
x = (x - OFFSET_X) / scale
y = (self:height() - y) / scale
table.insert(bodies, makeBody(x, y, math.random() * 1.5, math.random()))
end
end
function win:paint(p, w, h)
for i=#bodies,1,-1 do
-- Reverse order to be able to remove bodies from inside the
-- loop.
local elem = bodies[i]
if not drawElement(elem, p, w, h) then
-- remove
world:DestroyBody(elem.body)
table.remove(bodies, i)
end
end
end
-- This is our little game loop.
while true do
sleep(timeStep * 1000)
-- Instruct the world to perform a single step of simulation.
-- It is generally best to keep the time step and iterations fixed.
world:Step(timeStep, velocityIterations, positionIterations)
win:update()
end
-- When the world destructor is called, all bodies and joints are freed. This can
-- create orphaned pointers, so be careful about your world management.
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment