Created
January 18, 2012 21:54
-
-
Save gaspard/1636042 to your computer and use it in GitHub Desktop.
Simple Box2D demo with Lubyk
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
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