Table of Contents
25. Module box2d¶
Box 2D physics is an open source C++ engine for simulating rigid bodies in 2D.
The library Box 2D is available as a plugin/module.
The version and status of box2d can be found here.
Note
Important
function onTouchDown(key,x,y) local box2d_scale = tPhysic:getScale() x,y = mbm.to2dw(x,y) x,y = x / box2d_scale, y / box2d_scale -- box2d x,y world can be used now. end
25.1. box2d Methods¶
25.1.1. box2d getVersion¶
- getVersion
Get the current version of box2d.
Example:
require "box2d"
version = box2d:getVersion()
print(version)
25.1.2. box2d new¶
- new(number * gravity_x, number * gravity_y number * scale_box_2d, number * velocityIterations, number * positionIterations, number * multiplyStep)
Create a new instance of a box2d.
- Parameters
number – gravity in the axis x, default is
0.0.number – gravity in the axis y, default is
-90.8.number – scale to apply in the world default is
10.number – velocity iterations default is
10.number – position iterations default is
3.number – multiply step default is
1.
- Returns
box2d table.
Example:
require "box2d"
local gravity_x = 0
local gravity_y = -90.8
local scale_box_2d = 10
local velocityIterations = 10
local positionIterations = 3
local multiplyStep = 1
tPhysic = box2d:new(gravity_x,gravity_y,scale_box_2d,velocityIterations,positionIterations,multiplyStep)
print('Gravity :', tPhysic:getGravity())
print('Scale :', tPhysic:getScale())
print('Velocity iteration :', tPhysic:getVelocityIterations())
print('Position iteration :', tPhysic:getPositionIterations())
print('Multiply step :', tPhysic:getMultiply())
require "box2d"
tPhysic = box2d:new() --no arguments needed (same as before)
print('Gravity :', tPhysic:getGravity())
print('Scale :', tPhysic:getScale())
print('Velocity iteration :', tPhysic:getVelocityIterations())
print('Position iteration :', tPhysic:getPositionIterations())
print('Multiply step :', tPhysic:getMultiply())
Figure 25.2 Creating box2d instance without arguments¶
25.1.3. box2d contact listener¶
When bodies move around in the physics scene and bounce off each other, Box 2D will handle all the necessary collision detection and response so you don’t need to worry about that.
But the whole point of making a physics game is that occasionally something should happen in the game as a result of some of the bodies hitting each other eg. when the player touches a monster he should die, or a ball bouncing on the ground should make a sound etc.
A way to get this information back from the physics engine is using this abstracted contact listener implemented by the engine.
There are four callbacks to handle collision detection in Box 2D and the engine implemented them all (abstracted way).
- BeginContact
Called when two fixtures begin to touch. It has the following signature:
function onBeginContact(tMesh_a, tMesh_b) end
- EndContact
Called when two fixtures cease to touch. It has the following signature:
function onEndContact(tMesh_a, tMesh_b) end
- PreSolve
Called several times per step. Is called after a contact is updated. It has the following signature:
function onPreSolve(tMesh_a, tMesh_b, tManifold) end
Note
This is called only for awake bodies.This is called even when the number of contact points is zero.This is not called for sensors.If you set the number of contact points to zero, you will not get an EndContact callback. However, you may get a BeginContact callback the next step.See manifold table for more information.
- PostSolve
Called several times per step. This lets you inspect a contact after the solver is finished. This is useful for inspecting impulses. It has the following signature:
function onPostSolve(tMesh_a, tMesh_b, tImpulse) end
Note
This is only called for contacts that are touching, solid, and awake.The b2ContactImpulse used by the engine has the following members:
tImpulse = { count = 0, normalImpulses = {[1] = 0, [2] = 0}, tangentImpulses = {[1] = 0, [2] = 0}}
- setContactListener(function onBeginContact, function onEndContact, function onPreSolve, function onPostSolve)¶
- Parameters
function – onBeginContact callback (may be
nil).function – onEndContact callback (may be
nil).function – onPreSolve callback (may be
nil).function – onPostSolve callback (may be
nil).
Example:
require "box2d"
function print_manifold(tManifold)
print('type:',tManifold.type)
print('pointCount:',tManifold.pointCount)
print('localNormal.x:',tManifold.localNormal.x)
print('localNormal.x:',tManifold.localNormal.y)
print('localPoint.x:',tManifold.localPoint.x)
print('localPoint.x:',tManifold.localPoint.y)
for i =1, #tManifold.points do
print('point:',i)
print('\tlocalPoint.x:',tManifold.points[1].localPoint.x)
print('\tlocalPoint.y:',tManifold.points[1].localPoint.y)
print('\tnormalImpulse:',tManifold.points[1].normalImpulse)
print('\ttangentImpulse:',tManifold.points[1].tangentImpulse)
end
print('\n')
end
-- Callbacks
function onBeginContact(tMesh_a, tMesh_b)
print('\n')
print('Begin contact:')
print('Collision:',tMesh_a.name,tMesh_b.name)
end
function onEndContact(tMesh_a, tMesh_b)
print('\n')
print('End contact:')
print('Collision:',tMesh_a.name,tMesh_b.name)
end
function onPreSolve(tMesh_a, tMesh_b, tManifold)
print('\n')
print('onPreSolve:')
print('Collision:',tMesh_a.name,tMesh_b.name)
print_manifold(tManifold)
end
function onPostSolve(tMesh_a, tMesh_b, tImpulse)
print('\n')
print('Impulse:')
print('Impulse.count:', tImpulse.count)
print('Impulse.normalImpulses[1]:', tImpulse.normalImpulses[1])
print('Impulse.normalImpulses[2]:', tImpulse.normalImpulses[2])
print('Impulse.tangentImpulses[1]:', tImpulse.tangentImpulses[1])
print('Impulse.tangentImpulses[2]:', tImpulse.tangentImpulses[2])
end
-- End callbacks
mbm.setColor(1,1,1) --set background color to white
tPhysic = box2d:new()
tShapeQuad = shape:new('2dw',-10, 500)
tShapeCircle = shape:new('2dw',50 , 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeBigCircle = shape:new('2dw',200,800)
tShapeQuad.name = 'rectangle'
tShapeCircle.name = 'circle'
tShapeBigCircle.name = 'big circle'
tShapeGround.name = 'ground'
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeBigCircle:create('circle',200,200)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeBigCircle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:setContactListener(onBeginContact,onEndContact,onPreSolve,onPostSolve)
camera = mbm.getCamera('2d')
camera.y = 300
Figure 25.3 Example setContactListener box2d¶
25.1.4. box2d gravity¶
- getGravity¶
Return gravity used by box2d.
- Returns
numbergravity x,numbergravity y - of box2d.
Example:
require "box2d"
tPhysic = box2d:new()
print('Gravity :', tPhysic:getGravity())
- setGravity(number gravity_x, number gravity_y)¶
Set a new gravity to box2d.
- Parameters
number – gravity in the axis x.
number – gravity in the axis y.
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setGravity(-3,95.8)
25.1.5. box2d iterations¶
- getVelocityIterations¶
Return the velocity iterations used by box2d.
- Returns
numbervelocity iterations - of box2d.
Example:
require "box2d"
tPhysic = box2d:new()
print('Velocity iteration :', tPhysic:getVelocityIterations())
- getPositionIterations¶
Return the position iterations used by box2d.
- Returns
numberposition iterations - of box2d.
Example:
require "box2d"
tPhysic = box2d:new()
print('Velocity iteration :', tPhysic:getPositionIterations())
25.1.6. box2d manifold¶
A manifold table has the following structure:
tManifold = {
type = 'circles' or 'face_a' or 'face_b',
pointCount = 0,
localNormal = {x = 0, y = 0 },
localPoint = {x = 0, y = 0 },
points = {
[1] = {
localPoint = {x = 0, y = 0 },
normalImpulse = 0,
tangentImpulse = 0
},
[2] = {
localPoint = {x = 0, y = 0 },
normalImpulse = 0,
tangentImpulse = 0
},
}
- getManifolds(tBody, boolean * checkIsTouching, boolean * checkIsEnabled)¶
- param renderizable
body.
- param boolean
checkIsTouching instruct to check b2Contact::IsTouching() from Box2d (default if
false).- param boolean
checkIsEnabled instruct to check b2Contact::IsEnabled() from Box2d (default if
false).- return
table- manifold array.
Example:
--this is not a real example
function print_manifold(tManifold)
print('type:', tManifold.type)
print('pointCount:', tManifold.pointCount)
print('localNormal.x:', tManifold.localNormal.x)
print('localNormal.x:', tManifold.localNormal.y)
print('localPoint.x:', tManifold.localPoint.x)
print('localPoint.x:', tManifold.localPoint.y)
for i =1, #tManifold.points do
print('point:', i)
print('\tlocalPoint.x:', tManifold.points[1].localPoint.x)
print('\tlocalPoint.y:', tManifold.points[1].localPoint.y)
print('\tnormalImpulse:', tManifold.points[1].normalImpulse)
print('\ttangentImpulse:', tManifold.points[1].tangentImpulse)
end
print('\n')
end
--when is colliding otherwise will not have manifold.
local tManifolds = tPhysic:getManifolds(tMesh_a)
for i =1, #tManifolds do
print('\n')
print('Manifold index:',i)
print_manifold(tManifolds[i])
end
Figure 25.4 Example of output printing manifold structure.¶
- setManifolds(tManifolds)¶
- param table
manifolds previously got using getManifolds method.
Example:
require "box2d"
-- Callbacks
function onPreSolve(tMesh_a, tMesh_b, tManifold)
local tManifolds = tPhysic:getManifolds(tMesh_a)
for i =1, #tManifolds do
print('tManifold index ', i)
-- change something in the manifold
end
tPhysic:setManifolds(tMesh_a,tManifolds)
end
-- End callbacks
mbm.setColor(1,1,1) --set background color to white
tPhysic = box2d:new()
tShapeQuad = shape:new('2dw',-10, 500)
tShapeCircle = shape:new('2dw',50 , 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeBigCircle = shape:new('2dw',200,800)
tShapeQuad.name = 'rectangle'
tShapeCircle.name = 'circle'
tShapeBigCircle.name = 'big circle'
tShapeGround.name = 'ground'
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeBigCircle:create('circle',200,200)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeBigCircle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:setContactListener(nil,nil,onPreSolve,nil)
Important
Do not modify the manifold unless you understand the internals of Box2D.
25.1.7. box2d world manifold¶
A manifold world table has the following structure:
tWorldManifold = { normal = {x = 0, y = 0 },
separations = [1] = 0, [2] = 0,
points = {[1] = {x = 0, y = 0},
[2] = {x = 0, y = 0}}
- getWorldManifold(tBody)¶
- param renderizable
body.
- return
table- world manifold array.
Example:
require "box2d"
function print_manifold_world(tWorldManifold)
print('normal.x:',tWorldManifold.normal.x)
print('normal.x:',tWorldManifold.normal.y)
print('separations[1]:',tWorldManifold.separations[1])
print('separations[2]:',tWorldManifold.separations[2])
for i =1, #tWorldManifold.points do
print('point:',i)
print('\tx:',tWorldManifold.points[1].x)
print('\ty:',tWorldManifold.points[1].y)
end
print('\n')
end
-- Callbacks
function onPreSolve(tMesh_a, tMesh_b, tManifold)
local tWorldManifolds = tPhysic:getWorldManifolds(tMesh_a)
for i =1, #tWorldManifolds do
print('WorldManifold index ', i)
print_manifold_world(tWorldManifolds[i])
end
end
-- End callbacks
mbm.setColor(1,1,1) --set background color to white
tPhysic = box2d:new()
tShapeQuad = shape:new('2dw',-10, 500)
tShapeCircle = shape:new('2dw',50 , 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeBigCircle = shape:new('2dw',200,800)
tShapeQuad.name = 'rectangle'
tShapeCircle.name = 'circle'
tShapeBigCircle.name = 'big circle'
tShapeGround.name = 'ground'
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeBigCircle:create('circle',200,200)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeBigCircle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:setContactListener(nil,nil,onPreSolve,nil)
camera = mbm.getCamera('2d')
camera.y = 300
Figure 25.5 Example of accessing world manifold¶
25.1.8. box2d multiply¶
multiply parameter manipulates it doing literally a multiplication.world->Step(delta * multiplyStep, velocityIterations, positionIterations);
- getMultiply¶
Return the multiply step used by box2d.
- Returns
numbermultiply step - of box2d.
Example:
require "box2d"
tPhysic = box2d:new()
print('Multiply step :', tPhysic:getMultiply())
- setMultiply(number multiply_step)¶
Set a new multiply step to box2d.
- Parameters
number – multiply step to the box2d, default is
1.0.
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setMultiply(2)
25.1.9. box2d scale¶
The engine provide an internal scale to be able to adapt to any size of objects.
The default value is
10.
Here what the engine does internally to get values:
for(auto mesh : box_2d->all_meshes)
{
auto body = mesh->body;
if(body->typePhysics != b2_staticBody)
{
const b2Vec2 pos = body->GetPosition();
mesh->position.x = pos.x * box_2d->scale;
mesh->position.y = pos.y * box_2d->scale;
mesh->angle.z = body->GetAngle();
}
}
Here what the engine does internally to set values:
auto body = mesh->body;
const float scalePercentage = 1.0f / box_2d->scale;
const b2Vec2 position(mesh->position.x * scalePercentage, mesh->position.y * scalePercentage);
body->SetTransform(position,mesh->angle.z);
body->SetAwake(true);
Note
Setting scale to 1 makes the original behavior from box2d.
It means that if you suspect that this scale is interfering in yours result then just set it to 1.
require "box2d"
tPhysic = box2d:new()
print('Scale :', tPhysic:getScale())
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(20)
25.1.10. box2d pause¶
- pause
Pause the simulation of box2d.
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:pause()
25.1.11. box2d ray cast¶
Ray casting is often used to find out what objects are in a certain part of the world. A ray is just a straight line, and you can use a function provided by box2d to check if the line crosses a body. You can also find out what the
normalis at the point the line hits the body.The points
x_start,y_startandx_end,y_endare used to define a start, end and direction for the ray, and the max fraction specifies how far along the ray should be checked for an intersection.The following image may make this clearer.
Remark about fraction:
A fraction of 0 means the start of line, fraction of 1 means the end of line and in this figure, the fraction of 2 would intersect the shape.
A ray cast have the following signature:
function onRayCast(tMesh,x,y,nx,ny,fraction)
return fraction -- Zero means to end the ray cast
end
Note
If you return 0 the ray cast is ended by box2d
- rayCast(number x_start, number y_start, number x_end, number y_end, function onRayCastCallBack)
- Parameters
number – x start point of the ray-cast.
number – y start point of the ray-cast.
number – x end point of the ray-cast.
number – y end point of the ray-cast.
function – call back function ray-cast.
Example:
require "box2d"
--Ray cast callback
function onRayCast(tMesh,x,y,nx,ny,fraction)
message = string.format('Crossed line: %s, at x:%g y:%g normal nx:%g ny:%g fraction:%g',tMesh.name,x,y,nx,ny,fraction)
print(message)
tMesh:setColor(0.7,0,0)
tShapePoint:setPos(x,y)
tShapePoint.visible = true
return fraction --if you return 0 it means end of ray-cast
end
mbm.setColor(1,1,1) --set background color to white
local gravity_x = 0
local gravity_y = -9.8 --very slow to be able to see
tPhysic = box2d:new(gravity_x,gravity_y)
line_start = {x = -300, y = 200}
line_end = {x = 300, y = 50}
tLine = line:new('2dw')
tLine:add({line_start.x,line_start.y,line_end.x,line_end.y})
tLine:setColor(0,0,1) -- Blue color
tShapeQuad = shape:new('2dw',-20, 500)
tShapeCircle = shape:new('2dw',50 , 300)
tShapeGround = shape:new('2dw',0,-50)
tShapePoint = shape:new('2dw')
tShapeQuad.name = 'rectangle'
tShapeCircle.name = 'circle'
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapePoint:create('circle',20,20)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addStaticBody(tShapeGround)
function onLoop(delta,fps)
tShapeQuad:setColor(0.7,0,0.7) --reset the shape's color
tShapeCircle:setColor(0.7,0,0.7) --reset the shape's color
tShapePoint.visible = false
local pStart = {x = line_start.x , y = line_start.y }
local pEnd = {x = line_end.x , y = line_end.y }
tPhysic:rayCast(pStart.x,pStart.y,pEnd.x,pEnd.y,onRayCast)
end
Figure 25.6 Performing ray cast box2d¶
25.1.12. box2d start¶
require "box2d"
tPhysic = box2d:new()
tPhysic:start() --resume the simulation
25.1.13. box2d queryAABB¶
- queryAABB(number lowerBound_x, number lowerBound_y, number upperBound_x, number upperBound_y, function onQueryAABBBox2d)
Perform a AABB algorithm collision for all objects given the bound.
The callback is called in case of collision.
It has to have the following signature:
function onQueryAABBBox2d(tMesh)
end
Example:
require "box2d"
mbm.setColor(1,1,1) --set background color to white
function onQueryAABBBox2d(tMesh)
print('Collide with:',tMesh.name)
if tMesh.name == 'circle' then
tLine:setColor(1,0,0) -- red for circle
elseif tMesh.name == 'rectangle' then
tLine:setColor(0,0,1) --blue for rectangle
end
end
local gravity_x = 0
local gravity_y = -9.8 --very slow to be able to see
tPhysic = box2d:new(gravity_x,gravity_y)
local lowerBound = {x = 0, y = 0}
local upperBound = {x = 100, y = 100}
tLine = line:new('2dw')
tLine:add( {lowerBound.x,lowerBound.y,
lowerBound.x,upperBound.y,
upperBound.x,upperBound.y,
upperBound.x,lowerBound.y,
lowerBound.x,lowerBound.y})
tLine:setColor(1,1,1) --white color means no colision
tShapeQuad = shape:new('2dw',-20, 500)
tShapeCircle = shape:new('2dw',50 , 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad.name = 'rectangle'
tShapeCircle.name = 'circle'
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeGround:create('rectangle',500,20)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addStaticBody(tShapeGround)
function onLoop(delta)
tPhysic:queryAABB(lowerBound.x,lowerBound.y,upperBound.x,upperBound.y,onQueryAABBBox2d)
end
Figure 25.7 Performing query AABB colision¶
25.2. box2d Body¶
Bodies are the fundamental objects in the physics scene, but they are not what you actually see bouncing around and colliding with each other. Body represent the actual physics and for this engine, is a kind of glue beteween the actual body and any renderizable.
You can think of a body as the properties of an object that you cannot see (draw) or touch (collide with) but the engine will copy the position and angle to the current object.
The main properties of bodies for box2d are:
- Mass
how heavy it is
- Velocity
how fast and which direction it’s moving
- Rotational inertia
how much effort it takes to start or stop spinning
- Angular velocity
how fast and which way it’s rotating
- Location
where it is. This is the position of object (
x,y)
- Angle
which way it is facing. This is the angle
azof object
There are three types of body available for box2d: static, dynamic and kinematic. The engine implement them all.
Any renderizable object can be added to box2d to be simulated with its physics properties, however, it makes sense for 2D objects.
The body is based on physics properties which can be modified through setPhysics from meshDebug object.
25.2.1. Bullet body¶
- setBullet(tBody, boolean value)¶
Should this body be treated like a bullet for continuous collision detection?
- Parameters
renderizable – body.
boolean – value.
Example:
tPhysic:setBullet(tBody,true)
25.2.2. Character body¶
A Character body is a dynamic body but using fixed rotation and do not allowing to sleep.
Let’s see an example:
require "box2d"
mbm.setColor(1,1,1) --set background color to white
local gravity_x = 0
local gravity_y = -9.8 --very slow to be able to see
tPhysic = box2d:new(gravity_x,gravity_y)
tShapeQuad = shape:new('2dw',-310, 50)
tShapeCircle = shape:new('2dw', 0, 300)
tShapeTriangle = shape:new('2dw', 50, 500)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
local density, friction, restitution = 1, 10, 0.8 -- restitution 0.1 -> 0.8 (super)
tPhysic:addDynamicBody(tShapeCircle,density, friction, restitution)
tPhysic:addKinematicBody(tShapeQuad)
tPhysic:setLinearVelocity(tShapeQuad,2,0) -- move right 2 unit per second
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:setFixedRotation(tShapeTriangle,true)
tPhysic:setSleepingAllowed(tShapeTriangle,false)
tPhysic:addStaticBody(tShapeGround)
Figure 25.8 Creating character body¶
25.2.3. Damping options body¶
- setAngularDamping(tBody, number angular_damping)¶
- Parameters
renderizable – body.
number – angular damping.
Example:
tPhysic:setAngularDamping(tBody,15)
25.2.4. Density option body¶
- setDensity(tBody, number density, boolean * reset_mass)
Set the density of all fixtures in the body.
The optional flag reset_mass instruct to call b2Body::ResetMassData to update the body’s mass.
- Parameters
renderizable – body.
number – density.
boolean – reset mass flag, default is
true.
Example:
tPhysic:setDensity(tBody,10,true)
25.2.5. Destroy body¶
- destroyBody(tBody)¶
- Parameters
renderizable – body.
Example:
tPhysic:destroyBody(tBody)
Note
The engine will destroy the body in the next cycle.
25.2.6. Dynamic body¶
Dynamic body can move, spin and also be influenced by the gravity.
- addDynamicBody(renderizable mesh, number * density, number * friction, number * restitution, number * reduceX, number * reduceY, boolean * isSensor, boolean * isBullet)¶
Create a new instance of a
dynamicbody.- Parameters
renderizable – any type of mesh previouslly loaded according.
number – density default is
1.0.number – friction default is
10.0.number – restitution default is
0.1.number – scale of reduction on
xaxis. default is1.0(real size).number – scale of reduction on
yaxis. default is1.0(real size).boolean – sensor flag (
trueorfalse) default isfalse.boolean – bullet flag (
trueorfalse) default isfalse.
- Returns
body table.
For this example let’s create differents types of dynamic bodies:
require "box2d"
mbm.setColor(1,1,1)
local gravity_x = 0
local gravity_y = -9.8 --very slow to be able to see
tPhysic = box2d:new(gravity_x,gravity_y)
tShapeQuad = shape:new('2dw',-100, 720)
tShapeCircle = shape:new('2dw', 0, 500)
tShapeTriangle = shape:new('2dw', 50, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
local density, friction, restitution = 1, 10, 0.8 -- restitution 0.1 -> 0.8 (super)
tPhysic:addDynamicBody(tShapeCircle,density, friction, restitution)
density = 10
tPhysic:addDynamicBody(tShapeQuad,density) --heavy
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
Figure 25.9 Creating three dynamic bodies¶
25.2.7. Filter options body¶
- setEnable(tBody, boolean value)¶
Disable or enable a body changing internally the flag maskBits for each fixture in the body.
- Parameters
renderizable – body.
boolean – value.
Example:
require "box2d"
mbm.setColor(1,1,1)
local gravity_x = 0
local gravity_y = -9.8 --very slow to be able to see
tPhysic = box2d:new(gravity_x,gravity_y)
tShapeQuad = shape:new('2dw',-100, 300)
tShapeCircle = shape:new('2dw', 0, 200)
tShapeTriangle = shape:new('2dw', 50, 100)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeQuad) --heavy
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:setEnable(tShapeCircle,false)
Figure 25.10 Enable/disable box2d body¶
Internally it will change all fixture mask bits as is showing bellow:
const uint16 maskBits = enable ? 0xFFFF : 0;
b2Fixture* fixtureList = body->GetFixtureList();
while (fixtureList)
{
b2Filter oldFilter(fixtureList->GetFilterData());
oldFilter.maskBits = maskBits;
fixtureList->SetFilterData(oldFilter);
fixtureList = fixtureList->GetNext();
}
- setFilter(tBody * body, b2Filter filter)¶
Set the contact filtering data.
If body is not supplied it will set the filter for all bodies.
The default values are
0x0001for categoryBits and0xFFFFfor maskBits, or in other words every fixture says:‘I am a thing and I will collide with every other thing,’
- Parameters
renderizable – body (optional).
b2Filter – filter box2d.
The filter shall have this members (default values):
tFilter =
{ categoryBits = 0x0001, -- I am (16 bits)
maskBits = 0xFFFF, -- Collide with (16 bits)
groupIndex = 0} -- Group collision (override collision). (16 bits)
- categoryBits
The collision category bits. Normally you would just set one bit.
- maskBits
The collision mask bits. This states the categories that this shape would accept for collision.
- groupIndex
Collision groups allow a certain group of objects to never collide (negative) or always collide (positive). Zero means no collision group. Non-zero group filtering always wins against the mask bits.
Example:
require "box2d"
mbm.setColor(1,1,1)
local gravity_x = 0
local gravity_y = -9.8 --very slow to be able to see
tPhysic = box2d:new(gravity_x,gravity_y)
tFilterA = { categoryBits = 1, -- I am A (0000-0001)
maskBits = 132, -- Collide with C,D (1000-0100)
groupIndex = 0} -- Override collision
tFilterB = { categoryBits = 2, -- I am B (0000-0010)
maskBits = 128, -- Collide with D (1000-0000)
groupIndex = 0} -- Override collision
tFilterC = { categoryBits = 4, -- I am C (0000-0100)
maskBits = 129, -- Collide with A,D (1000-0001)
groupIndex = 0} -- Override collision
tFilterD = { categoryBits = 128, -- I am D (1000-0000)
maskBits = 255, -- Collide with all (1111-1111)
groupIndex = 0} -- Override collision
tShapeQuad = shape:new('2dw', -20, 300)
tShapeCircle = shape:new('2dw', 0, 200)
tShapeTriangle = shape:new('2dw', 50, 100)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:setFilter(tShapeQuad, tFilterA)
tPhysic:setFilter(tShapeCircle, tFilterB)
tPhysic:setFilter(tShapeTriangle, tFilterC)
tPhysic:setFilter(tShapeGround, tFilterD)
Figure 25.11 box2d setFilter¶
25.2.8. Force options body¶
- applyForce(tBody, number fx, number fy, number * wx, number *wy)
Apply a gradual force at a world point. If the force is not applied at the center of mass, it will generate a torque and affect the angular velocity.
This function always wake up the body.
- Parameters
renderizable – body.
number – fx force world, usually in Newtons (N).
number – fy force world, usually in Newtons (N).
number – wx point the world position of the point of application.
number – wy point the world position of the point of application.
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(10)
tShapeQuad = shape:new('2dw',-310, 50)
tShapeCircle = shape:new('2dw', 0, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',40,40)
tShapeCircle:create('circle',40,40)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addStaticBody(tShapeGround)
function onKeyDown(key)
local force = 20000
local wx,wy = tPhysic:getWorldCenter(tShapeQuad) --same effect as applyForceToCenter
if mbm.getKeyCode('up') == key then -- in this example we keep pressing to up
tPhysic:applyForce(tShapeQuad,0 ,force, wx, wy)
elseif mbm.getKeyCode('left') == key then
tPhysic:applyForce(tShapeQuad,-force,0, wx, wy)
elseif mbm.getKeyCode('right') == key then -- and in the air right
tPhysic:applyForce(tShapeQuad,force,0, wx, wy)
end
end
Figure 25.12 box2d applying force¶
- applyForceToCenter(tBody, number fx, number fy)¶
Apply a force at a world point at the center of mass,
- Parameters
renderizable – body.
number – fx force world, usually in Newtons (N).
number – fy force world, usually in Newtons (N).
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(10)
tShapeQuad = shape:new('2dw',-310, 50)
tShapeCircle = shape:new('2dw', 0, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',40,40)
tShapeCircle:create('circle',40,40)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addStaticBody(tShapeGround)
function onKeyDown(key)
local force = 20000
if mbm.getKeyCode('up') == key then
tPhysic:applyForceToCenter(tShapeQuad,0 ,force)
elseif mbm.getKeyCode('left') == key then
tPhysic:applyForceToCenter(tShapeQuad,-force,0)
elseif mbm.getKeyCode('right') == key then
tPhysic:applyForceToCenter(tShapeQuad,force,0) -- in this example we keep pressing to right
end
end
Figure 25.13 box2d applying force to center¶
- applyLinearImpulse(tBody, number fx, number fy, number * wx, number *wy)
Apply an impulse at a point. This immediately modifies the velocity. It also modifies the angular velocity if the point of application is not at the center of mass. This wakes up the body.
- Parameters
renderizable – body.
number – fx force world, usually in Newtons (N).
number – fy force world, usually in Newtons (N).
number – wx point the world position of the point of application.
number – wy point the world position of the point of application.
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(10)
tShapeQuad = shape:new('2dw',-310, 50)
tShapeCircle = shape:new('2dw', 0, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',40,40)
tShapeCircle:create('circle',40,40)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addStaticBody(tShapeGround)
function onKeyDown(key)
local force = 2000
local wx,wy = tPhysic:getWorldCenter(tShapeQuad)
if mbm.getKeyCode('up') == key then
tPhysic:applyLinearImpulse(tShapeQuad,0 ,force, wx, wy)
elseif mbm.getKeyCode('left') == key then
tPhysic:applyLinearImpulse(tShapeQuad,-force,0, wx, wy)
elseif mbm.getKeyCode('right') == key then -- in this example we pressed once to right
tPhysic:applyLinearImpulse(tShapeQuad,force,0, wx, wy)
end
end
Figure 25.14 box2d applying linear impulse¶
- applyLinearImpulseToCenter(tBody, number fx, number fy)¶
Apply an impulse to the center of mass. This immediately modifies the velocity.
- Parameters
renderizable – body.
number – fx force world, usually in Newtons (N).
number – fy force world, usually in Newtons (N).
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(10)
tShapeQuad = shape:new('2dw',-310, 50)
tShapeCircle = shape:new('2dw', 0, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',40,40)
tShapeCircle:create('circle',40,40)
tShapeGround:create('rectangle',1000,20)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addStaticBody(tShapeGround)
function onKeyDown(key)
local force = 2000
if mbm.getKeyCode('up') == key then
tPhysic:applyLinearImpulseToCenter(tShapeQuad,0 ,force) -- in this example we pressed once to up
elseif mbm.getKeyCode('left') == key then
tPhysic:applyLinearImpulseToCenter(tShapeQuad,-force,0)
elseif mbm.getKeyCode('right') == key then
tPhysic:applyLinearImpulseToCenter(tShapeQuad,force,0)
end
end
Figure 25.15 box2d applying linear impulse to center¶
- applyAngularImpulse(tBody, number angular_impulse, boolean * wake)¶
Apply an angular impulse.
- Parameters
renderizable – body.
number – angular impulse in units of kg*m*m/s.
boolean – wake up the body (default is
true).
Example:
tPhysic:applyAngularImpulse(tBody,50,true)
25.2.9. Friction options body¶
- setFriction(tBody, number friction, boolean update_contact_list)¶
Set the coefficient of friction. By default the engine also set the friction on contact list.
- Parameters
renderizable – body.
number – friction coefficient.
boolean – update contact list flag (default is
true).
Example:
tPhysic:setFriction(tBody,5,true)
25.2.10. Gravity options body¶
- getGravityScale(tBody)
Get the gravity scale of the body.
- Parameters
renderizable – body.
- Returns
number- gravity scale
Example:
local gravity_scale = tPhysic:getGravityScale(tBody)
- setGravityScale(tBody, number gravity_scale)
Set the gravity scale of the body.
- Parameters
renderizable – body.
number – gravity scale.
Example:
tPhysic:setGravity(tBody,2.0)
25.2.11. Inertia options body¶
- getInertia(tBody)¶
Get the rotational inertia of the body about the local origin.
- Parameters
renderizable – body.
- Returns
number- The rotational inertia, usually in kg-m^2.
Example:
local inertia = tPhysic:getInertia(tBody)
25.2.12. Mass options body¶
- getMass(tBody)¶
Get the total mass of the body.
- Parameters
renderizable – body.
- Returns
number- the mass, usually in kilograms (kg).
Example:
local mass = tPhysic:getMass(tBody)
- setMass(tBody)¶
The mass of the shape, usually in kilograms.
- Parameters
renderizable – body.
number – mass.
Example:
tPhysic:setMass(tBody,10)
25.2.13. Kinematic body¶
A kinematic body is very similar to a static body because, when it collides with a dynamic body it always holds its ground, and forces the dynamic body to retreat out of the way. The difference is that a kinematic body can move.
- addKinematicBody(renderizable mesh, number * density, number * friction, number * restitution, number * reduceX, number * reduceY, boolean * isSensor)¶
Create a new instance of a
kinematicbody.- Parameters
renderizable – any type of mesh previouslly loaded according.
number – density default is
1.0.number – friction default is
10.0.number – restitution default is
0.1.number – scale of reduction on
xaxis. default is1.0(real size).number – scale of reduction on
yaxis. default is1.0(real size).boolean – sensor flag (
trueorfalse) default isfalse.
- Returns
body table.
For this example let’s create a kinematic body as a square:
require "box2d"
mbm.setColor(1,1,1) --set background color to white
local gravity_x = 0
local gravity_y = -9.8 --very slow to be able to see
tPhysic = box2d:new(gravity_x,gravity_y)
tShapeQuad = shape:new('2dw',-310, 50)
tShapeCircle = shape:new('2dw', 0, 500)
tShapeTriangle = shape:new('2dw', 50, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
local density, friction, restitution = 1, 10, 0.8 -- restitution 0.1 -> 0.8 (super)
tPhysic:addDynamicBody(tShapeCircle,density, friction, restitution)
tPhysic:addKinematicBody(tShapeQuad)
tPhysic:setLinearVelocity(tShapeQuad,2,0) -- move right 2 unit per second
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
Figure 25.16 Creating kinematic body¶
25.2.14. Position options body¶
- getPosition(tBody)¶
Get the body position NOT considering the box2d scale .
- Parameters
renderizable – body.
- Returns
numberx -number- y .
Example:
require "box2d"
local x,y = tPhysic:getPosition(tBody)
print('raw position :',x,y)
print('scaled position:',tBody.x,tBody.y)
-- possible output using scale default (10)
-- raw position : -2 7.929474
-- scaled position: -20 79.29475
25.2.15. Restitution options body¶
- setRestitution(tBody, number restitution, boolean update_contact_list)¶
Set the coefficient of restitution. By default the engine also set the restitution on contact list.
- Parameters
renderizable – body.
number – restitution coefficient.
boolean – update contact list flag (default is
true).
Example:
tPhysic:setRestitution(tBody,10,true)
25.2.16. Rotation options body¶
- setFixedRotation(tBody, boolean value)¶
Set this body to have fixed rotation. This causes the mass to be reset.
- Parameters
renderizable – body.
boolean – value.
Example:
tPhysic:setFixedRotation(tBody,true)
25.2.17. Sleep options body¶
- setSleepingAllowed(tBody, boolean value)¶
Disable sleeping on body. If you disable sleeping, the body will be woken.
- Parameters
renderizable – body.
boolean – value.
Example:
tPhysic:setSleepingAllowed(tBody,false)
25.2.18. State options body¶
- isActive(tBody)¶
Get the active state of the body.
- Parameters
renderizable – body.
- Returns
boolean- is active
Example:
local is_active = tPhysic:isActive(tBody)
print('Body is active?:', tostring(is_active))
- isAwake(tBody)¶
Get the sleeping state of this body.
- Parameters
renderizable – body.
- Returns
boolean- is awake
Example:
local is_awake = tPhysic:isActive(tBody)
print('Body is awake?:', tostring(is_awake))
- setActive(tBody, boolean value)¶
Set the active state of the body. An inactive body is not simulated and cannot be collided with or woken up. If you pass a flag of true, all fixtures will be added to the broad-phase. If you pass a flag of false, all fixtures will be removed from the broad-phase and all contacts will be destroyed. Fixtures and joints are otherwise unaffected. You may continue to create/destroy fixtures and joints on inactive bodies. Fixtures on an inactive body are implicitly inactive and will not participate in collisions, ray-casts, or queries. Joints connected to an inactive body are implicitly inactive. An inactive body is still owned by a b2World object and remains in the body list.
- Parameters
renderizable – body.
boolean – value.
Example:
tPhysic:setActive(tBody,true)
- setAwake(tBody, boolean value)¶
Set the sleep state of the body. A sleeping body has very low CPU cost.
- Parameters
renderizable – body.
boolean – value.
Example:
tPhysic:setAwake(tBody,false)
25.2.19. Static body¶
when a static body collides with a dynamic body, it always holds its ground, and forces the dynamic body to retreat out of the way. The static body will never move.
- addStaticBody(renderizable mesh, number * density, number * friction, number * reduceX, number * reduceY, boolean * isSensor)¶
Create a new instance of a
staticbody.- Parameters
renderizable – any type of mesh previouslly loaded according.
number – density default is
0.0.number – friction default is
0.3.number – scale of reduction on
xaxis. default is1.0(real size).number – scale of reduction on
yaxis. default is1.0(real size).boolean – sensor flag (
trueorfalse) default isfalse.
- Returns
body table.
For this example let’s create a ground which represent the static body:
require "box2d"
mbm.setColor(1,1,1)
local gravity_x = 0
local gravity_y = -9.8 --very slow to be able to see
tPhysic = box2d:new(gravity_x,gravity_y)
tShapeQuad = shape:new('2dw',-20, 720)
tShapeCircle = shape:new('2dw',100, 500)
tShapeTriangle = shape:new('2dw',50 , 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeQuad:create('rectangle',100,100)
tShapeCircle:create('circle',100,100)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',500,20)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
Figure 25.17 Creating a static body named tShapeGround¶
25.2.20. Test point on body¶
- testPoint(tBody, number x, number y)¶
Test a point for containment in all fixture from a body.
- Parameters
renderizable – body.
number – x in world coordinates.
number – y in world coordinates.
- Returns
boolean- hit any fixture
Example:
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tPhysic:setScale(15)
tShapeQuad = shape:new('2dw', -20, -20)
tShapeQuad:create('rectangle', 100,200)
tPhysic:addStaticBody(tShapeQuad)
function onTouchMove(key,x,y)
x,y = mbm.to2dw(x,y)
if tPhysic:testPoint(tShapeQuad,x,y) then
tShapeQuad:setColor(0.8,0,0)
else
tShapeQuad:setColor(0.8,0,0.8)
end
end
Figure 25.18 testPoint box2d¶
25.2.21. Torque options body¶
- applyTorque(tBody, number torque, boolean * wake)¶
Apply a torque. This affects the angular velocity without affecting the linear velocity of the center of mass.
- Parameters
renderizable – body.
number – torque about the z-axis (out of the screen), usually in N-m.
boolean – wake up the body (default is
true).
Example:
tPhysic:applyTorque(tBody,50,true)
25.2.22. Transform options body¶
Important
You should consider the box2d scale to everything related to any transform method to real world and vice versa.
- setTransform(tBody, number * x, number * y, number * angle)¶
Set a new position of the body’s origin and rotation.
Manipulating a body’s transform may cause non-physical behavior but sometimes it is desired.
If not supplied any of arguments it will use the own position and angle.
- Parameters
number – x position of body.
number – y position of body.
number – angle
zof body.
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(10) -- setTransform method considers box2d scale.
tShapeQuad = shape:new('2dw')
tShapeQuad:create('rectangle',100,100)
tPhysic:addDynamicBody(tShapeQuad)
tShapeQuad:setPos(55,33) -- will not change the position since box2d is in control
tShapeQuad.az = math.rad(15) -- tilt 15 degree
tPhysic:setTransform(tShapeQuad) -- Now we say to box 2d to use this new position and z angle
-- tPhysic:setTransform(tShapeQuad,55,33,math.rad(15)) --same as above
Important
const float scalePercentage = 1.0f / box2d->scale;
const b2Vec2 position(newPosition->x * scalePercentage,newPosition->y * scalePercentage);
body->SetTransform(position,newAngleDegree);
- getWorldCenter(tBody)¶
Get the world position of the center of mass.
- Parameters
renderizable – body.
- Returns
numberx -number- y .
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(1)
tShapeQuad = shape:new('2dw',45,38) --put some place different from origin
tShapeQuad:create('rectangle',100,100)
tPhysic:addStaticBody(tShapeQuad)
local px, py = tPhysic:getWorldCenter(tShapeQuad)
tShapePoint = shape:new('2dw')
tShapePoint:create('circle',10,10)
tShapePoint:setPos(px,py)
tShapePoint:setColor(0,0,1) -- our blue point
print('px:',px,'py:',py)
Figure 25.19 box2d getWorldCenter method¶
- getWorldPoint(tBody, number x, number y)¶
The function getWorldPoint is used to convert a location relative to the body (body coordinates) into world coordinates.
- Parameters
renderizable – body.
number – x point on the body measured relative the the body’s origin.
number – y point on the body measured relative the the body’s origin.
- Returns
numberx -number- y .
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(1)
tShapeQuad = shape:new('2dw',66,99) --put some place different from origin
tShapeQuad:create('rectangle',100,100)
tShapeQuad.az = math.rad(10) -- tilt 10 degree
tPhysic:addStaticBody(tShapeQuad)
local x, y = 50,50 -- we know the size
local px, py = tPhysic:getWorldPoint(tShapeQuad,x,y)
tShapePoint = shape:new('2dw')
tShapePoint:create('circle',10,10)
tShapePoint:setPos(px,py)
tShapePoint:setColor(0,0,1) -- our blue point
print('px:',px,'py:',py)
Figure 25.20 box2d getWorldPoint method¶
- getWorldVector(tBody, number x, number y)¶
Get the world coordinates of a vector given the local coordinates.
- Parameters
renderizable – body.
number – x local fixed in the body.
number – y local fixed in the body.
- Returns
numberx -number- y .
Example:
require "box2d"
tPhysic = box2d:new()
tPhysic:setScale(1)
tShapeQuad = shape:new('2dw',50,50)
tShapeQuad:create('rectangle',100,100)
tShapeQuad.az = math.rad(180) -- tilt 180 degree
tPhysic:addStaticBody(tShapeQuad)
local x, y = 100,100
local px, py = tPhysic:getWorldVector(tShapeQuad,x,y)
tShapePoint = shape:new('2dw')
tShapePoint:create('circle',10,10)
tShapePoint:setPos(px,py)
tShapePoint:setColor(0,0,1) -- our blue point
print('px:',px,'py:',py)
Figure 25.21 box2d getWorldVector method¶
- getLocalPoint(tBody)¶
Gets a local point relative to the body’s origin given a world point.
- Parameters
renderizable – body.
number – x world coordinates.
number – y world coordinates.
- Returns
numberx -number- y corresponding local point relative to the body’s origin.
Example:
local x,y = tPhysic:getLocalPoint(tBody,10,5)
- getLocalCenter(tBody)¶
Get the local position of the center of mass.
- Parameters
renderizable – body.
- Returns
numberx -number- y local center.
Example:
local x,y = tPhysic:getLocalCenter(tBody)
25.2.23. Type options body¶
- setType(tBody, string type)¶
Set the type of body. This may alter the mass and velocity.
Acceptable types are:
static,kinematicordynamic.- Parameters
renderizable – body.
string – type of body.
Example:
tPhysic:setType(tBody,'static')
- getType(tBody)¶
Retrieve the body type.
The possible types are:
static,kinematicordynamic.- Parameters
renderizable – body.
- Returns
string- type
Example:
local type_body = tPhysic:getType(tBody)
25.2.24. Velocity options body¶
- getLinearVelocity(tBody)¶
Get the linear velocity of the center of mass.
- Parameters
renderizable – body.
- Returns
numberx -number- y the linear velocity of the center of mass.
Example:
local lx,ly = tPhysic:getLinearVelocity(tBody)
- getAngularVelocity(tBody)¶
Get the angular velocity.
- Parameters
renderizable – body.
- Returns
number- angular velocity in radians/second.
Example:
local angular_velocity = tPhysic:getAngularVelocity(tBody)
- setAngularVelocity(tBody, number omega)¶
Set the angular velocity.
- Parameters
renderizable – body.
number – omega. the new angular velocity in radians/second.
Example:
local omega = math.rad(15)
tPhysic:setAngularVelocity(tBody,omega)
- setLinearVelocity(tBody, number x, number y)¶
Set the linear velocity of the center of mass.
- Parameters
renderizable – body.
number – x. the new linear velocity of the center of mass.
number – y. the new linear velocity of the center of mass.
Example:
tPhysic:setLinearVelocity(tBody,50,2)
25.3. box2d Joint¶
Box2D has a lot of joints that can be used to connect two bodies. These joints mostly are to be used to simulate the interaction between objects to form hinges, pistons, ropes, wheels, pulleys, vehicles, chains, etc. Learning how to use joints effectively helps to create a more engaging and interesting scene. The method used to create a joint is defined here.
Joint common properties
Although each joint has a different behavior, they have some properties in common. Here are the properties which are common to build each joint:
tJoint = { name = 'my joint name', collideConnected = false, }Also for some joints you have to need to specify details for the specific type of joint that you are making. This commonly includes an anchor point on each body, limits on the range of movement, and motor settings.
- Anchor points
Typically a point on each body is given as the location around which the bodies must interact. Depending on the joint type, this point will be the center of rotation, the locations to keep a certain distance apart, etc.
- Joint limits
Revolute and prismatic joints can be given limits, which places a restriction on how far the bodies can rotate or slide.
- Joint motors
Revolute, prismatic and line (wheel) joints can be given motor settings, which means that instead of spinning or sliding around freely, the joint acts as if it had it’s own power source. The motor is given a maximum force or torque, and this can be used in combination with a target velocity to spin or slide bodies in relation to each other.
25.3.1. Joints definition¶
Let’s see the joints available for box2d and its characteristics:
25.3.1.1. Distance joint¶
- Distance
A point on each body will be kept at a fixed distance apart.
This requires defining an anchor point on both bodies and the non-zero length of the distance joint. The definition uses local anchor points so that the initial configuration can violate the constraint slightly. This helps when saving and loading a game.
Warning
Do not use a zero or short length.
Here the table definition:
tJoint =
{
name = 'distance',
localAnchorA = {x = 0.0, y = 0.0},
localAnchorB = {x = 0.0, y = 0.0},
length = 1.0,
frequencyHz = 0.0,
dampingRatio = 0.0,
collideConnected = false
}
Hint
localAnchorA, localAnchorB and length.pos_1 = tPhysic:getPosition(mesh_1) -- position from box2d might be different if is there scale pos_2 = tPhysic:getPosition(mesh_2) -- position from box2d might be different if is there scale tJoint = { anchor1 = {x = pos_1.x, y = pos_1.y}, -- default values anchor2 = {x = pos_2.y, y = pos_2.y}, -- default values -- others parameters from table definition ... }
Of course if you pass any of localAnchorA, localAnchorB and length it will be overridden.
25.3.1.2. Friction joint¶
- Friction
Reduces the relative motion between the two bodies.
Here the table definition:
tJoint =
{
name = 'friction',
localAnchorA = {x = 0, y = 0},
localAnchorB = {x = 0, y = 0},
maxForce = 0.0,
maxTorque = 0.0,
collideConnected = false
}
Hint
localAnchorA and localAnchorB.tJoint = { anchor = {x = 0, y = 0}, -- Default value -- others parameters from table definition ... }
Of course if you pass any of localAnchorA or localAnchorB it will be overridden.
25.3.1.3. Gear joint¶
- Gear
Controls two other joints (revolute or prismatic) so that the movement of one affects the other.
This definition requires two existing revolute or prismatic joints (any combination will work).
Here the table definition:
tJoint = { name = 'gear', ratio = 1.0, indexA = absolute_index_joint_A, indexB = absolute_index_joint_B, collideConnected = false }
Note
It is mandatory the body 1 and 2 have joint.The index have preference, in other words, the engine will look first for the absolute index.
25.3.1.4. Motor joint¶
- Motor
Controls the relative motion between two bodies.
A typical usage is to control the movement of a dynamic body with respect to the ground.
Here the table definition:
tJoint = { name = 'motor', linearOffset = { x = 0, y = 0}, angularOffset = 0.0, maxForce = 1.0, maxTorque = 1.0, correctionFactor = 0.3, collideConnected = false, }
25.3.1.5. Mouse joint¶
- Mouse
Pulls a point on one body to a location in the world.
This requires a world target point, tuning parameters, and the time step.
Here the table definition:
tJoint = { name = 'mouse', target = {x = 0, y = 0}, maxForce = 0.0, frequencyHz = 5.0, dampingRatio = 0.7, collideConnected = false, }
Note
Mouse joint does not need a second body however to keep the signature, we pass it twice on create joint method.
25.3.1.6. Prismatic joint¶
- Prismatic
The relative rotation of the two bodies is fixed, and they can slide along an axis.
This requires defining a line of motion using an axis and an anchor point. The definition uses local anchor points and a local axis so that the initial configuration can violate the constraint slightly. The joint translation is zero when the local anchor points coincide in world space. Using local anchors and a local axis helps when saving and loading a game.
Here the table definition:
tJoint =
{
name = 'prismatic',
localAnchorA = {x = 0, y=0},
localAnchorB = {x = 0, y=0},
localAxisA = {x = 1, y=0}, -- Must be normalized
referenceAngle = 0.0,
enableLimit = false,
lowerTranslation = 0.0,
upperTranslation = 0.0,
enableMotor = false,
maxMotorForce = 0.0,
motorSpeed = 0.0,
collideConnected = false,
}
Hint
localAnchorA, localAnchorB and localAxisA.tJoint = { anchor = {x = 0, y = 0}, -- Default value. It initialize localAnchorA and localAnchorB axis = {x = 0, y = 1}, --Default value. It initialize localAxisA. must be normalized -- others parameters from table definition ... }
Of course if you pass any of localAnchorA, localAnchorB and localAxisA it will be overridden.
25.3.1.7. Pulley joint¶
- Pulley
A point on each body will be kept within a certain distance from a point in the world.
This requires two ground anchors, two dynamic body anchor points, and a pulley ratio.
Here the table definition:
tJoint =
{
name = 'pulley',
groundAnchorA = {x = -1.0 , y = 1.0},
groundAnchorB = {x = 1.0 , y = 1.0},
localAnchorA = {x = -1.0 , y = 0.0},
localAnchorB = {x = 1.0 , y = 0.0},
lengthA = 0.0,
lengthB = 0.0,
ratio = 1.0,
collideConnected = true,
}
Hint
localAnchorA, localAnchorB, groundAnchorA, groundAnchorB, lengthA and lengthB.localAnchorA, localAnchorB, groundAnchorA, groundAnchorB, lengthA and lengthB.tJoint = { anchorA = {x = body_a.x, y = body_a.y}, -- default values comes from body a anchorB = {x = body_b.x, y = body_b.y}, -- default values comes from body b -- others parameters from table definition ... }
Of course if you pass any of localAnchorA, localAnchorB, groundAnchorA, groundAnchorB, lengthA and lengthB it will be overridden.
lengthA + lengthA == constant.lengthA + ratio * lengthB == constant25.3.1.8. Revolute joint¶
- Revolute
A hinge or pin, where the bodies rotate about a common point.
This requires defining an anchor point where the bodies are joined. The definition uses local anchor points so that the initial configuration can violate the constraint slightly. You also need to specify the initial relative angle for joint limits. This helps when saving and loading a game. The local anchor points are measured from the body’s origin rather than the center of mass because:
you might not know where the center of mass will be.
if you add/remove shapes from a body and recompute the mass,the joints will be broken.
Here the table definition:
tJoint =
{
name = 'revolute',
localAnchorA = { x = 0.0, y = 0.0},
localAnchorB = { x = 0.0, y = 0.0},
referenceAngle = 0.0,
lowerAngle = 0.0,
upperAngle = 0.0,
maxMotorTorque = 0.0,
motorSpeed = 0.0,
enableLimit = false,
enableMotor = false,
collideConnected = false,
}
Hint
localAnchorA, localAnchorB and referenceAngle.pos_mesh_2 = tPhysic:getPosition(mesh_2) tJoint = { anchor = {x = pos_mesh_2.x, y = pos_mesh_2.y}, -- Default value, position from mesh '2' -- others parameters from table definition ... }
Of course if you pass any of localAnchorA, localAnchorB or referenceAngle it will be overridden.
25.3.1.9. Rope joint¶
- Rope
A point on each body will be constrained to a maximum distance apart.
This requires two body anchor points and a maximum lengths.
Here the table definition:
tJoint = { name = 'rope', localAnchorA = { x =-1.0, y = 0.0}, localAnchorB = { x = 1.0, y = 0.0}, maxLength = 0.0, collideConnected = false, }
Warning
The maximum length of the rope must be larger than b2_linearSlop (0.005) or the joint will have no effect.
25.3.1.10. Weld joint¶
- Weld
Holds the bodies at the same orientation.
You need to specify local anchor points where they are attached and the relative body angle. The position of the anchor points is important for computing the reaction torque.
Here the table definition:
tJoint =
{
name = 'weld',
localAnchorA = { x = 0.0, y = 0.0},
localAnchorB = { x = 0.0, y = 0.0},
referenceAngle = 0.0,
frequencyHz = 0.0,
dampingRatio = 0.0,
collideConnected = false,
}
Hint
localAnchorA, localAnchorB and referenceAngle.pos_mesh_2 = tPhysic:getPosition(mesh_2) tJoint = { anchor = {x = pos_mesh_2.x, y = pos_mesh_2.y}, -- Default value, position from mesh '2' -- others parameters from table definition ... }
Of course if you pass any of localAnchorA, localAnchorB or referenceAngle it will be overridden.
25.3.1.11. Wheel joint¶
- Wheel
A combination of revolute and prismatic joints, useful for modeling vehicle suspension. (old
linejoint).
This requires defining a line of motion using an axis and an anchor point. The definition uses local anchor points and a local axis so that the initial configuration can violate the constraint slightly. The joint translation is zero when the local anchor points coincide in world space. Using local anchors and a local axis helps when saving and loading a game.
Here the table definition:
tJoint =
{
name = 'wheel',
localAnchorA = { x = 0, y = 0 },
localAnchorB = { x = 0, y = 0 },
localAxisA = { x = 1, y = 0 },
enableMotor = false,
maxMotorTorque = 0.0,
motorSpeed = 0.0,
frequencyHz = 2.0,
dampingRatio = 0.7,
collideConnected = false,
}
Hint
localAnchorA, localAnchorB and localAxisA.tJoint = { anchor = {x = 0, y = 0}, -- Default value. It initialize localAnchorA and localAnchorB axis = {x = 0, y = 1}, --Default value. It initialize localAxisA. -- others parameters from table definition ... }
Of course if you pass any of localAnchorA, localAnchorB and localAxisA it will be overridden.
25.3.2. Creating joint¶
- joint(tBody_A, tBody_B, tJoint)¶
The signature is always like this. The first body then the second and the joint table definition.
- Parameters
renderizable – first body.
renderizable – second body.
table – joint definition. see box2d joint
- Returns
number- index absolute of joint. (zero is error).
Note
number indicating the absolute index in the engine for this joint.25.3.2.1. Distance joint¶
Next, an example of joint using distance joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tShapeQuad = shape:new('2dw',-200, 720)
tShapeCircle1 = shape:new('2dw',-100, 400)
tShapeCircle2 = shape:new('2dw', 100, 400)
tShapeTriangle = shape:new('2dw', 50, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeWall = shape:new('2dw',300,100)
tShapeQuad:create('rectangle',100,100)
tShapeCircle1:create('circle',100,100)
tShapeCircle2:create('circle',80,80)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
tShapeWall:create('rectangle',20,200)
local density, friction, restitution = 0.5, 10, 1.0
tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution)
tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeWall)
tJoint =
{
name = 'distance',
localAnchorA = {x = 0.0, y = 0.0},
localAnchorB = {x = 0.0, y = 0.0},
--length: we are omitting the distance let the engine calculate it
frequencyHz = 0.0,
dampingRatio = 0.0,
collideConnected = false
}
local indexJoint = tPhysic:joint(tShapeCircle1,tShapeCircle2,tJoint)
Figure 25.22 Distance joint¶
25.3.2.2. Friction joint¶
Next, an example of joint using friction joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tShapeQuad = shape:new('2dw',-200, 720)
tShapeCircle1 = shape:new('2dw',-100, 400)
tShapeCircle2 = shape:new('2dw', 100, 400)
tShapeTriangle = shape:new('2dw', 50, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeWall = shape:new('2dw',300,100)
tShapeQuad:create('rectangle',100,100)
tShapeCircle1:create('circle',100,100)
tShapeCircle2:create('circle',80,80)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
tShapeWall:create('rectangle',20,200)
local density, friction, restitution = 0.5, 10, 1.0
tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution)
tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeWall)
tJoint =
{
name = 'friction',
localAnchorA = {x = 0, y = 0},
localAnchorB = {x = 0, y = 0},
maxForce = 5000.0,
maxTorque = 5000.0,
collideConnected = true
}
local indexJoint = tPhysic:joint(tShapeQuad,tShapeGround,tJoint)
Figure 25.23 Friction joint¶
25.3.2.3. Gear joint¶
Next, an example of joint using gear joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tShapeBoxMain = shape:new('2dw',0, 100)
tShapeBoxLeft = shape:new('2dw',-50, 150)
tShapeBoxRight = shape:new('2dw',50, 150)
tShapeCircle = shape:new('2dw',400, 500)
tShapeGround = shape:new('2dw',0,40)
tShapeRightWall = shape:new('2dw',450,0)
tShapeBoxMain:create('rectangle',100,100)
tShapeBoxLeft:create('rectangle',50,50)
tShapeBoxRight:create('rectangle',50,50)
tShapeCircle:create('circle',100,100)
tShapeGround:create('rectangle',1000,20)
tShapeRightWall:create('rectangle',20,400)
tShapeGround.az = math.rad(2) --tilt a litle bit
tPhysic:addDynamicBody(tShapeBoxMain)
tPhysic:addDynamicBody(tShapeBoxLeft)
tPhysic:addDynamicBody(tShapeBoxRight)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeRightWall)
local size_box = {x = 0, y = 0}
size_box.x, size_box.y = tShapeBoxMain:getSize()
size_box.x = size_box.x / tPhysic:getScale() --consider the box2d scale
size_box.y = size_box.y / tPhysic:getScale() --consider the box2d scale
local corner_box_left = {x = size_box.x / 2,y = size_box.y / 2} -- corner of the box (top,left)
local corner_box_right = {x = -size_box.x / 2,y = size_box.y / 2} -- corner of the box (top,right)
--[[
corner box top left -> *-------* <- corner_box top,right
| main |
| box |
|-------|
]]
tJointLeft =
{
name = 'revolute',
localAnchorA = corner_box_left, --in the corner of the box A (top,left)
localAnchorB = {x = 0, y =0}, --in the center of the left box
referenceAngle = tShapeBoxLeft.az - tShapeBoxMain.az,
lowerAngle = math.rad(-90), -- no effect since enableLimit is false
upperAngle = math.rad(45), -- no effect since enableLimit is false
maxMotorTorque = 10000.0,
motorSpeed = 10.0,
enableLimit = false,
enableMotor = false,
collideConnected = false,
}
tJointRight =
{
name = 'revolute',
localAnchorA = corner_box_right, --in the corner of the box A (top,right)
localAnchorB = {x = 0, y =0}, --in the center of the rigth box
referenceAngle = tShapeBoxLeft.az - tShapeBoxMain.az,
lowerAngle = math.rad(-90), -- no effect since enableLimit is false
upperAngle = math.rad(45), -- no effect since enableLimit is false
maxMotorTorque = 10000.0,
motorSpeed = 10.0,
enableLimit = false,
enableMotor = false,
collideConnected = false,
}
local indexA = tPhysic:joint(tShapeBoxMain,tShapeBoxLeft,tJointLeft)
local indexB = tPhysic:joint(tShapeBoxMain,tShapeBoxRight,tJointRight)
tJLeft = tPhysic:getJoint(tShapeBoxLeft)
tJRight = tPhysic:getJoint(tShapeBoxRight)
tJoint =
{
name = 'gear',
ratio = 1.0,
indexA = indexA,
indexB = indexB,
collideConnected = false
}
local indexJointGear = tPhysic:joint(tShapeBoxLeft,tShapeBoxRight,tJoint)
Figure 25.24 Gear joint¶
25.3.2.4. Motor joint¶
Next, an example of joint using motor joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tShapeQuad = shape:new('2dw',-200, 520)
tShapeCircle1 = shape:new('2dw',-80, 400)
tShapeCircle2 = shape:new('2dw', 100, 400)
tShapeTriangle = shape:new('2dw', 50, 300)
tShapeGround = shape:new('2dw',0,-300)
tShapeRightWall = shape:new('2dw',450,0)
tShapeLeftWall = shape:new('2dw',-450,0)
tShapeQuad:create('rectangle',100,100)
tShapeCircle1:create('circle',200,200,10) --low resolution of the circle
tShapeCircle2:create('circle',80,80)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
tShapeRightWall:create('rectangle',20,400)
tShapeLeftWall:create('rectangle',20,400)
local density, friction, restitution = 0.5, 10, 1.0
tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution)
tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeLeftWall)
tPhysic:addStaticBody(tShapeRightWall)
tJoint =
{
name = 'motor',
linearOffset = { x = 15, y = 0}, --relative distance between body 2 and body 1
angularOffset = math.rad(180.0), --relative angle between body 2 and body 1
maxForce = 100000.0,
maxTorque = 10000.0,
correctionFactor = 1.3,
collideConnected = false,
}
local indexJoint = tPhysic:joint(tShapeQuad,tShapeCircle1,tJoint)
Figure 25.25 Motor joint¶
25.3.2.5. Mouse joint¶
Next, an example of joint using mouse joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tPhysic:setScale(10) --set our desired scale
tShapeQuad = shape:new('2dw',-200, 300)
tShapeCircle1 = shape:new('2dw',-100, 300)
tShapeCircle2 = shape:new('2dw', 100, 300)
tShapeTriangle = shape:new('2dw', 50, 300)
tShapeGround = shape:new('2dw',0,-350)
tShapeLeftWall = shape:new('2dw',-400,0)
tShapeRightWall = shape:new('2dw',400,0)
tShapeUpWall = shape:new('2dw',0,350)
tShapeQuad:create('rectangle',100,100)
tShapeCircle1:create('circle',100,100)
tShapeCircle2:create('circle',80,80)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
tShapeRightWall:create('rectangle',20,700)
tShapeLeftWall:create('rectangle',20,700)
tShapeUpWall:create('rectangle',1000,20)
local density, friction, restitution = 0.5, 10, 1.0
tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution)
tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeRightWall)
tPhysic:addStaticBody(tShapeLeftWall)
tPhysic:addStaticBody(tShapeUpWall)
tAllDynamicObject = {} --store all dynamic objects that we want to apply mouse joint
table.insert(tAllDynamicObject,tShapeQuad)
table.insert(tAllDynamicObject,tShapeCircle1)
table.insert(tAllDynamicObject,tShapeCircle2)
table.insert(tAllDynamicObject,tShapeTriangle)
--our mouse joint table
tJoint =
{
name = 'mouse',
target = {x=0,y=0}, -- updated in the moment that we click on object and keep clicked
maxForce = 0, -- updated according to mass
frequencyHz = 30.0,
dampingRatio = 0.7,
collideConnected = false,
}
tMouseJoint = nil --point to mouse joint when created
tMeshJoint = nil --point to mesh that we have selected (clicked)
--called onTouchDown and onTouchMove
function setTarget(x,y)
x , y = x / tPhysic:getScale(),y / tPhysic:getScale() -- we have to consider the scale
if tMouseJoint then
tMouseJoint:setTarget(x,y)
end
tJoint.target.x,tJoint.target.y = x,y
end
function onTouchDown(key,x,y)
x,y = mbm.to2dw(x,y)
for i = 1, #tAllDynamicObject do
local tMesh = tAllDynamicObject[i]
if tPhysic:testPoint(tMesh,x,y) and tMouseJoint == nil then
tJoint.maxForce = 1000 * tPhysic:getMass(tMesh)
setTarget(x,y) -- update the target
if tPhysic:joint(tMesh,tMesh,tJoint) > 0 then
tMouseJoint = tPhysic:getJoint(tMesh)
tMeshJoint = tAllDynamicObject[i]
break
end
end
end
end
function onTouchMove(key,x,y)
if tMouseJoint then
x , y = mbm.to2dw(x,y)
setTarget(x,y)-- update the target
end
end
function onTouchUp(key,x,y)
if tMouseJoint then
tPhysic:destroyJoint(tMeshJoint) --no long are holding the object, destroy it
tMouseJoint = nil --mark as nil
end
end
Figure 25.26 Mouse joint¶
Note
25.3.2.6. Prismatic joint¶
Next, an example of joint using prismatic joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tShapeBoxA = shape:new('2dw',-300, 100)
tShapeBoxB = shape:new('2dw',-350, 150)
tShapeCircle = shape:new('2dw',400, 500)
tShapeGround = shape:new('2dw',0,40)
tShapeRightWall = shape:new('2dw',450,0)
tShapeBoxA:create('rectangle',100,100)
tShapeBoxB:create('rectangle',50,10)
tShapeCircle:create('circle',100,100)
tShapeGround:create('rectangle',1000,20)
tShapeRightWall:create('rectangle',20,400)
tShapeGround.az = math.rad(2) --tilt a litle bit
tPhysic:addDynamicBody(tShapeBoxA)
tPhysic:addDynamicBody(tShapeBoxB)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeRightWall)
local size_box_a = {x = 0, y = 0}
size_box_a.x, size_box_a.y = tShapeBoxA:getSize()
size_box_a.x = size_box_a.x / tPhysic:getScale() --consider the box2d scale
size_box_a.y = size_box_a.y / tPhysic:getScale() --consider the box2d scale
local corner_box_a = {x = size_box_a.x / 2,y = -size_box_a.y / 2} -- corner of the box (bottom, right)
local size_box_b = {x = 0, y = 0}
size_box_b.x, size_box_b.y = tShapeBoxB:getSize()
size_box_b.x = size_box_b.x / tPhysic:getScale() --consider the box2d scale
size_box_b.y = size_box_b.y / tPhysic:getScale() --consider the box2d scale
local corner_box_b = {x = -size_box_b.x / 2,y = -size_box_b.y / 2} -- corner of the box (bottom left)
--[[
|-------|
| | |-------|
| box A | | |
|-------* <- corner box a bottom,right | box B |
corner box b bottom left -> *-------|
]]
tJoint =
{
name = 'prismatic',
localAnchorA = {x = corner_box_a.x, y = corner_box_a.y},
localAnchorB = {x = corner_box_b.x, y = corner_box_b.y},
localAxisA = {x = 0, y=1}, -- Direction of elevation (normalized)
referenceAngle = 0.0,
enableLimit = true,
lowerTranslation = 0.0,
upperTranslation = size_box_a.y, --How high? same as maximum of first box
enableMotor = false, --enable on key up
maxMotorForce = 50000.0,
motorSpeed = 5.0,
collideConnected = false,
}
local indexJoint = tPhysic:joint(tShapeBoxA,tShapeBoxB,tJoint)
tJointPrismatic = tPhysic:getJoint(tShapeBoxA)
function onKeyDown(key)
if mbm.getKeyCode('up') == key then
tJointPrismatic:enableMotor(true)
end
end
function onKeyUp(key)
if mbm.getKeyCode('up') == key then
tJointPrismatic:enableMotor(false)
end
end
Figure 25.27 Prismatic joint¶
25.3.2.7. Pulley joint¶
Next, an example of joint using pulley joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tPhysic:setScale(10)
tShapeBox1 = shape:new('2dw',-200, -80)
tShapeBox2 = shape:new('2dw', 200, -308)
tShapeGround = shape:new('2dw',0,-350)
tShapeGround:create('rectangle',1000,20)
tShapeBox1:create('rectangle',100,100)
tShapeBox2:create('rectangle',50,50)
tPhysic:addDynamicBody(tShapeBox1)
tPhysic:addDynamicBody(tShapeBox2)
tPhysic:addStaticBody(tShapeGround)
groundAnchorA = shape:new('2dw',-200,300)
groundAnchorB = shape:new('2dw',200,300)
groundAnchorA:create('circle',20,20)
groundAnchorB:create('circle',20,20)
size_box_2_y = select(2,tShapeBox2:getSize())
half_size_box_2_y = size_box_2_y / 2
box_2d_scale = tPhysic:getScale()
tJoint =
{
name = 'pulley',
groundAnchorA = {x = groundAnchorA.x / box_2d_scale , y = groundAnchorA.y / box_2d_scale},
groundAnchorB = {x = groundAnchorB.x / box_2d_scale , y = groundAnchorB.y / box_2d_scale},
localAnchorA = {x = 0.0 , y = 0.0},
localAnchorB = {x = 0.0 , y = half_size_box_2_y / box_2d_scale},
lengthA = 100.0 / box_2d_scale,
lengthB = 400.0 / box_2d_scale,
ratio = 1.0,
collideConnected = true,
}
local indexJoint = tPhysic:joint(tShapeBox1,tShapeBox2,tJoint)
Figure 25.28 Pulley joint¶
25.3.2.8. Revolute joint¶
Next, an example of joint using revolute joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tShapeBoxA = shape:new('2dw',0, 100)
tShapeBoxB = shape:new('2dw',50, 150)
tShapeCircle = shape:new('2dw',400, 500)
tShapeGround = shape:new('2dw',0,40)
tShapeRightWall = shape:new('2dw',450,0)
tShapeBoxA:create('rectangle',100,100)
tShapeBoxB:create('rectangle',50,50)
tShapeCircle:create('circle',100,100)
tShapeGround:create('rectangle',1000,20)
tShapeRightWall:create('rectangle',20,400)
tShapeGround.az = math.rad(2) --tilt a litle bit
tPhysic:addDynamicBody(tShapeBoxA)
tPhysic:addDynamicBody(tShapeBoxB)
tPhysic:addDynamicBody(tShapeCircle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeRightWall)
local size_box = {x = 0, y = 0}
size_box.x, size_box.y = tShapeBoxA:getSize()
size_box.x = size_box.x / tPhysic:getScale() --consider the box2d scale
size_box.y = size_box.y / tPhysic:getScale() --consider the box2d scale
local corner_box = {x = size_box.x / 2,y = size_box.y / 2} -- corner of the box (top,right)
--[[
|-------* <- corner_box top,right
| |
| box A |
|-------|
]]
-- If we omit local anchors A and B, the engine will use the second body to calculate it.
tJoint =
{
name = 'revolute',
localAnchorA = corner_box, --in the corner of the box A (top,right)
localAnchorB = {x = 0, y =0}, --in the center of the box B
referenceAngle = tShapeBoxB.az - tShapeBoxA.az,
lowerAngle = math.rad(-90), -- no effect since enableLimit is false
upperAngle = math.rad(45), -- no effect since enableLimit is false
maxMotorTorque = 10000.0,
motorSpeed = 10.0,
enableLimit = false,
enableMotor = true,
collideConnected = false,
}
local indexJoint = tPhysic:joint(tShapeBoxA,tShapeBoxB,tJoint)
Figure 25.29 Revolute joint¶
25.3.2.9. Rope joint¶
Next, an example of joint using rope joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tShapeQuad = shape:new('2dw',-200, 720)
tShapeCircle1 = shape:new('2dw',-100, 400)
tShapeCircle2 = shape:new('2dw', 100, 400)
tShapeTriangle = shape:new('2dw', 50, 300)
tShapeGround = shape:new('2dw',0,-50)
tShapeWall = shape:new('2dw',300,100)
tShapeQuad:create('rectangle',100,100)
tShapeCircle1:create('circle',100,100)
tShapeCircle2:create('circle',80,80)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
tShapeWall:create('rectangle',20,200)
local density, friction, restitution = 0.5, 10, 1.0
tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution)
tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeWall)
tJoint =
{
name = 'rope',
localAnchorA = { x =-1.0, y = 0.0},
localAnchorB = { x = 1.0, y = 0.0},
--maxLength = 0.0, -- let the engine calculate the max length according to the current position of the bodies
collideConnected = false,
}
local indexJoint = tPhysic:joint(tShapeCircle1,tShapeCircle2,tJoint)
Figure 25.30 Rope joint¶
25.3.2.10. Weld joint¶
Next, an example of joint using weld joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tShapeQuad = shape:new('2dw',-200, 520)
tShapeCircle1 = shape:new('2dw',-80, 400)
tShapeCircle2 = shape:new('2dw', 100, 400)
tShapeTriangle = shape:new('2dw', 50, 300)
tShapeGround = shape:new('2dw',0,-300)
tShapeRightWall = shape:new('2dw',450,0)
tShapeLeftWall = shape:new('2dw',-450,0)
tShapeQuad:create('rectangle',100,100)
tShapeCircle1:create('circle',200,200,10) --low resolution of the circle
tShapeCircle2:create('circle',80,80)
tShapeTriangle:create('triangle',100)
tShapeGround:create('rectangle',1000,20)
tShapeRightWall:create('rectangle',20,400)
tShapeLeftWall:create('rectangle',20,400)
local density, friction, restitution = 0.5, 10, 1.0
tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution)
tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution)
tPhysic:addDynamicBody(tShapeQuad)
tPhysic:addDynamicBody(tShapeTriangle)
tPhysic:addStaticBody(tShapeGround)
tPhysic:addStaticBody(tShapeLeftWall)
tPhysic:addStaticBody(tShapeRightWall)
local world_point_a = { x = 0, y = 0 }
local world_point_b = { x = 0, y = 0 }
world_point_a.x, world_point_a.y = tPhysic:getLocalPoint(tShapeQuad,0,0)
world_point_b.x, world_point_b.y = tPhysic:getLocalPoint(tShapeCircle1,0,0)
tJoint =
{
name = 'weld',
localAnchorA = world_point_a,-- If we omit local anchors A and B, the engine will use the second body to calculate it.
localAnchorB = world_point_b,-- If we omit local anchors A and B, the engine will use the second body to calculate it.
referenceAngle = tShapeQuad.az - tShapeCircle1.az, --if not supply, it will get the angle difference like this
frequencyHz = 0.0,
dampingRatio = 0.0,
collideConnected = false,
}
local indexJoint = tPhysic:joint(tShapeQuad,tShapeCircle1,tJoint)
Figure 25.31 Weld joint¶
25.3.2.11. Wheel joint¶
Next, an example of joint using wheel joint table.
require "box2d"
mbm.setColor(1,1,1)
tPhysic = box2d:new()
tPhysic:setScale(10)
tShapCar = shape:new('2dw', 0, 50)
tShapeWheel1 = shape:new('2dw',-50, 25)
tShapeWheel2 = shape:new('2dw', 50, 25)
tShapeGround = shape:new('2dw',0,-25)
tShapeGround:create('rectangle',1000,20)
tShapCar:create('rectangle',100,50)
tShapeWheel1:create('circle',50,50)
tShapeWheel2:create('circle',50,50)
tPhysic:addDynamicBody(tShapCar)
tPhysic:addDynamicBody(tShapeWheel1)
tPhysic:addDynamicBody(tShapeWheel2)
tPhysic:addStaticBody(tShapeGround)
-- Invert mass. See box2d tutorial the explanation
local massCar = tPhysic:getMass(tShapCar)
local massWheel = tPhysic:getMass(tShapeWheel1)
tPhysic:setMass(tShapeWheel1,massCar * 0.5)
tPhysic:setMass(tShapeWheel2,massCar * 0.5)
tPhysic:setMass(tShapCar, massWheel * 2)
tJoint =
{
name = 'wheel',
localAnchorA = { x = 0, y = 0 },
localAnchorB = { x = 0, y = 0 },
localAxisA = { x = 0, y = 1 },
enableMotor = true,
maxMotorTorque = 8000,
motorSpeed = 0.0,
frequencyHz = 3.0,
dampingRatio = 0.9,
collideConnected = false,
}
v1 = vec2:new()
v2 = vec2:new()
box_2d_scale = tPhysic:getScale()
--find the relative local of back wheel
v1:set(tShapCar.x,tShapCar.y)
v2:set(tShapeWheel1.x,tShapeWheel1.y)
v2:sub(v1)
v2:div(box_2d_scale)
tJoint.localAnchorA.x,tJoint.localAnchorA.y = v2.x,v2.y
local indexJoint1 = tPhysic:joint(tShapCar,tShapeWheel1,tJoint)
tShapCar.tJointWheel1 = tPhysic:getJoint(tShapeWheel1)
--find the relative local of front wheel
v1:set(tShapCar.x,tShapCar.y)
v2:set(tShapeWheel2.x,tShapeWheel2.y)
v2:sub(v1)
v2:div(box_2d_scale)
tJoint.localAnchorA.x, tJoint.localAnchorA.y = v2.x,v2.y
local indexJoint2 = tPhysic:joint(tShapCar,tShapeWheel2,tJoint)
tShapCar.tJointWheel2 = tPhysic:getJoint(tShapeWheel2)
motorSpeed = 500
direction_car = 0
function onKeyDown(key)
if mbm.getKeyCode('left') == key then
direction_car = 1
elseif mbm.getKeyCode('right') == key then
direction_car = -1
end
end
function onKeyUp(key)
if mbm.getKeyCode('left') == key or mbm.getKeyCode('right') == key then
direction_car = 0
end
end
function onLoop(delta)
tShapCar.tJointWheel1:setMotorSpeed(motorSpeed * direction_car)
tShapCar.tJointWheel2:setMotorSpeed(motorSpeed * direction_car)
end
Figure 25.32 Wheel joint¶
25.3.4. Active options¶
- isActive
Available for all joints
Check if both bodies are active given the joint.
- Returns
boolean- Both bodies are active?
Example:
local active = tJoint:isActive()
- setActive(boolean value)
Available for all joints
Set active option for both bodies given the joint.
- Parameters
boolean –
value- Set Active for both bodies
Example:
tJoint:setActive(true)
25.3.5. Angular offset options¶
local angular_offset = tJoint:getAngularOffset()
- setAngularOffset(number angular_offset)¶
Available for motor.
- Parameters
number – angular_offset.
Example:
local angular_offset = math.rad(10)
tJoint:setAngularOffset(angular_offset)
25.3.6. Anchor options¶
- getAnchorA¶
- return
numberx -number- y anchor on body ‘A’ in world coordinates.
Example:
local x,y = tJoint:getAnchorA()
- getAnchorB¶
- return
numberx -number- y anchor on body ‘B’ in world coordinates.
Example:
local x,y = tJoint:getAnchorB()
25.3.7. Correction factor options¶
- getCorrectionFactor¶
Available for motor.
- Returns
number- correction factor in range [0,1]
Example:
local correction = tJoint:getCorrectionFactor()
- setCorrectionFactor(table joint, number correction_factor)¶
Available for motor
- Parameters
number – correction factor in range [0,1]
Example:
local correction_factor = 0.5
tJoint:setCorrectionFactor(correction_factor)
25.3.8. Damping ratio options¶
- getDampingRatio¶
Available for distance , gear , wheel, weld .
- Returns
number- Damping ratio
Example:
local damping_ratio = tJoint:getDampingRatio()
- setDampingRatio(number damping_ratio)¶
Available for distance , gear , wheel, weld .
- Parameters
number – damping ratio.
Example:
local damping_ratio = 2
tJoint:setDampingRatio(damping_ratio)
25.3.9. Destroy joint¶
- destroyJoint(tBody)¶
- Parameters
renderizable – body.
Example:
tPhysic:destroyJoint(tBody)
Note
25.3.10. Force options¶
- getMaxForce¶
Available for mouse, friction, motor, prismatic.
Max motor force for prismatic.
- Returns
number- maximum friction force in newton.
Example:
local maximum_friction_force = tJoint:getMaxForce()
- setMaxForce(number max_friction_force)¶
Available for mouse, friction, motor, prismatic.
Max motor force for prismatic.Motor options joint
- Parameters
number – maximum friction force in newton.
Example:
local max_friction_force = 10
tJoint:setMaxForce(max_friction_force)
25.3.11. Frequency options¶
- setFrequencyHz(number hertz)¶
Available for distance , wheel, weld .
- Parameters
number – hertz.
Example:
local hertz = 30
tJoint:setFrequencyHz(hertz)
local hertz = tJoint:getFrequencyHz()
25.3.12. Get joint¶
- getJoint(tBody, number * absolute_index)¶
Retrieve a joint previously created passing any of body used to create th joint through the method joint and the absolute index (not mandatory).
- Parameters
renderizable – body.
number – absolute index of the joint in the engine. (this index can be invalid after destroying joint).
- Returns
table- joint
Example:
tJoint = tPhysic:getJoint(tBody,indexMyJoint)
25.3.13. Length options¶
local length = tJoint:getLength()
local length = 10
tJoint:setLength(length)
25.3.14. Limit options¶
local enable = true
tJoint:enableLimit(enable)
local lower, upper = tJoint:getLimits()
- setLimits(number lower, number upper)¶
Available for revolute, prismatic.
- Parameters
number – lower.
number – upper.
Example:
local lower, upper = 10, 10
tJoint:setLimits(lower,upper)
25.3.15. Linear offset options¶
local x,y = tJoint:getLinearOffset()
- setLinearOffset(number x, number y)¶
Available for motor
- Parameters
number – x (Frame A in Meters).
number – y (Frame A in Meters).
Example:
local x,y = 10,15
tJoint:setLinearOffset(x,y)
25.3.16. Motor options¶
- getMotorSpeed¶
Available for revolute, prismatic, wheel.
- Returns
number- speed in radian per second.
Example:
local motor_speed_rad = tJoint:getMotorSpeed() -- speed in radian per second
- setMotorSpeed(number speed)¶
Available for revolute, prismatic, wheel.
- Parameters
number – speed in radian per second.
Example:
local speed = math.rad(360)
tJoint:setMotorSpeed(speed)
local max_torque = tJoint:getMaxMotorTorque()
- setMaxMotorTorque(number max_torque)¶
Available for revolute, wheel, motor
- Parameters
number – max torque.
Example:
local torque = 5
tJoint:setMaxMotorTorque(torque)
- enableMotor(boolean value)¶
Available for revolute, prismatic, wheel.
- Parameters
boolean – value.
Example:
local enable = true
tJoint:enableMotor(enable)
25.3.17. Reaction options¶
- getReactionForce(number inv_delta)¶
Available for all joints
- Parameters
number – inv_delta.
- Returns
numberx -number- y reaction force on body B at the joint anchor in Newtons.
Example:
local inv_delta = 1/60
local x,y = tJoint:getReactionForce(inv_delta)
- getReactionTorque(number inv_delta)¶
Available for all joints
- Parameters
number – inv_delta.
- Returns
number- reaction torque on body B in N x m
Example:
local inv_delta = 1/60
local reaction_torque = tJoint:getReactionTorque(inv_delta)
25.3.18. Target options¶
- getTarget¶
- Available for mouse.You should consider the box2d scale to this method to transform to
2dwcoordinates.- Returns
numberx -number- y
Example:
local box2d_scale = tPhysic:getScale()
local x,y = tJoint:getTarget()
x,y = x * box2d_scale, y * box2d_scale
- setTarget(number x, number y)¶
- Available for mouse.You should consider the box2d scale to this method.
- Parameters
number – x.
number – y.
Example:
-- part of example here
function onTouchDown(key,x,y)
x,y = mbm.to2dw(x,y)
local box2d_scale = tPhysic:getScale()
x,y = x / box2d_scale, y / box2d_scale
tJoint:setTarget(x,y)
end