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

NOT all methods from Box 2D are wrapped.
The most complicated methods have examples.
It is desired to have more examples and methods wrapped, but for now, we consider it stable, faithful (to box2d) and good enough to develop a game.
If you need some method which is not wrapped you could make a pull request for it.

Important

Box 2D works in units and to be able to do a right adaptation, the engine uses a scale factor.
Always use function from box2d when related to position (locations).
E.g: Prefer to use box2d:getPosition instead of the position of renderizable:getPosition.
When transforming from 2d world to box2d consider box2d scale
Example:
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
  • numbergravity in the axis x, default is 0.0.

  • numbergravity in the axis y, default is -90.8.

  • numberscale to apply in the world default is 10.

  • numbervelocity iterations default is 10.

  • numberposition iterations default is 3.

  • numbermultiply 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())
_images/box_2d_example_1.png

Figure 25.1 Creating box2d instance

Other example:

 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())
_images/box_2d_example_2.png

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.

Note

b2Manifold from Box 2D has more member in the structure then this. The engine omit them.

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
  • functiononBeginContact callback (may be nil).

  • functiononEndContact callback (may be nil).

  • functiononPreSolve callback (may be nil).

  • functiononPostSolve 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
_images/box_2d_set_contact_listener.gif

Figure 25.3 Example setContactListener box2d

25.1.4. box2d gravity

getGravity

Return gravity used by box2d.

Returns

number gravity x, number gravity 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
  • numbergravity in the axis x.

  • numbergravity 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

number velocity iterations - of box2d.

Example:

 require "box2d"
 tPhysic = box2d:new()
 print('Velocity iteration :', tPhysic:getVelocityIterations())
getPositionIterations

Return the position iterations used by box2d.

Returns

number position 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
_images/box_2d_manifold.png

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
_images/box_2d_world_manifold.gif

Figure 25.5 Example of accessing world manifold

25.1.8. box2d multiply

Box 2D has a internal function which is called every step. This function is b2World::Step.
The first argument is delta regarding the amount of time to simulate, this should not vary.
The multiply parameter manipulates it doing literally a multiplication.
See how the engine does:
world->Step(delta * multiplyStep, velocityIterations, positionIterations);
getMultiply

Return the multiply step used by box2d.

Returns

number multiply 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

numbermultiply 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.

getScale

Return the scale used by box2d.

Returns

number scale - of box2d.

Example:

 require "box2d"
 tPhysic = box2d:new()
 print('Scale              :', tPhysic:getScale())
setScale(number scale)

Set a new scale to box2d.

Parameters

numberscale to the box2d.

Example:

 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 normal is at the point the line hits the body.

The points x_start, y_start and x_end, y_end are 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.

_images/box_2d_raycast_fraction.png

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
  • numberx start point of the ray-cast.

  • numbery start point of the ray-cast.

  • numberx end point of the ray-cast.

  • numbery end point of the ray-cast.

  • functioncall back function ray-cast.

It considers box2d scale.

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 loop(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
_images/box_2d_raycast.gif

Figure 25.6 Performing ray cast box2d

25.1.12. box2d start

start

Start or resume the simulation of box2d.

Example:

 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.

It considers box2d scale.

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 loop(delta)
     tPhysic:queryAABB(lowerBound.x,lowerBound.y,upperBound.x,upperBound.y,onQueryAABBBox2d)
 end
_images/box_2d_example_query_AABB.gif

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 az of 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
  • renderizablebody.

  • booleanvalue.

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)
_images/box_2d_example_character_body.gif

Figure 25.8 Creating character body

25.2.3. Damping options body

setAngularDamping(tBody, number angular_damping)
Parameters
  • renderizablebody.

  • numberangular 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
  • renderizablebody.

  • numberdensity.

  • booleanreset mass flag, default is true.

Example:

tPhysic:setDensity(tBody,10,true)

25.2.5. Destroy body

destroyBody(tBody)
Parameters

renderizablebody.

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 dynamic body.

Parameters
  • renderizable – any type of mesh previouslly loaded according.

  • numberdensity default is 1.0.

  • numberfriction default is 10.0.

  • numberrestitution default is 0.1.

  • numberscale of reduction on x axis. default is 1.0 (real size).

  • numberscale of reduction on y axis. default is 1.0 (real size).

  • booleansensor flag (true or false) default is false.

  • booleanbullet flag (true or false) default is false.

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)
_images/box_2d_example_creating_dynamic_body.gif

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
  • renderizablebody.

  • booleanvalue.

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)
_images/box_2d_setEnable.gif

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 0x0001 for categoryBits and 0xFFFF for maskBits, or in other words every fixture says:

‘I am a thing and I will collide with every other thing,’

Parameters
  • renderizablebody (optional).

  • b2Filterfilter 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)
_images/box_2d_setFilter.gif

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
  • renderizablebody.

  • numberfx force world, usually in Newtons (N).

  • numberfy force world, usually in Newtons (N).

  • numberwx point the world position of the point of application.

  • numberwy 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
_images/box_2d_example_applyForce.gif

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
  • renderizablebody.

  • numberfx force world, usually in Newtons (N).

  • numberfy 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
_images/box_2d_example_applyForceToCenter.gif

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
  • renderizablebody.

  • numberfx force world, usually in Newtons (N).

  • numberfy force world, usually in Newtons (N).

  • numberwx point the world position of the point of application.

  • numberwy 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
_images/box_2d_example_applyLinearImpulse.gif

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
  • renderizablebody.

  • numberfx force world, usually in Newtons (N).

  • numberfy 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
_images/box_2d_example_applyLinearImpulseToCenter.gif

Figure 25.15 box2d applying linear impulse to center

applyAngularImpulse(tBody, number angular_impulse, boolean * wake)

Apply an angular impulse.

Parameters
  • renderizablebody.

  • numberangular impulse in units of kg*m*m/s.

  • booleanwake 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
  • renderizablebody.

  • numberfriction coefficient.

  • booleanupdate 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

renderizablebody.

Returns

number - gravity scale

Example:

local gravity_scale = tPhysic:getGravityScale(tBody)
setGravityScale(tBody, number gravity_scale)

Set the gravity scale of the body.

Parameters
  • renderizablebody.

  • numbergravity 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

renderizablebody.

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

renderizablebody.

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
  • renderizablebody.

  • numbermass.

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 kinematic body.

Parameters
  • renderizable – any type of mesh previouslly loaded according.

  • numberdensity default is 1.0.

  • numberfriction default is 10.0.

  • numberrestitution default is 0.1.

  • numberscale of reduction on x axis. default is 1.0 (real size).

  • numberscale of reduction on y axis. default is 1.0 (real size).

  • booleansensor flag (true or false) default is false.

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)
_images/box_2d_example_creating_kinematic_body.gif

Figure 25.16 Creating kinematic body

25.2.14. Position options body

getPosition(tBody)

Get the body position NOT considering the box2d scale .

Parameters

renderizablebody.

Returns

number x - 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
  • renderizablebody.

  • numberrestitution coefficient.

  • booleanupdate 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
  • renderizablebody.

  • booleanvalue.

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
  • renderizablebody.

  • booleanvalue.

Example:

tPhysic:setSleepingAllowed(tBody,false)

25.2.18. State options body

isActive(tBody)

Get the active state of the body.

Parameters

renderizablebody.

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

renderizablebody.

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
  • renderizablebody.

  • booleanvalue.

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
  • renderizablebody.

  • booleanvalue.

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 static body.

Parameters
  • renderizable – any type of mesh previouslly loaded according.

  • numberdensity default is 0.0.

  • numberfriction default is 0.3.

  • numberscale of reduction on x axis. default is 1.0 (real size).

  • numberscale of reduction on y axis. default is 1.0 (real size).

  • booleansensor flag (true or false) default is false.

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)
_images/box_2d_example_creating_static_body.gif

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.

It considers box2d scale.

Parameters
  • renderizablebody.

  • numberx in world coordinates.

  • numbery 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
_images/box_2d_testPoint.gif

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
  • renderizablebody.

  • numbertorque about the z-axis (out of the screen), usually in N-m.

  • booleanwake 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
  • numberx position of body.

  • numbery position of body.

  • numberangle z of 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

This method is the only one that considers box2d scale making a automatically calculation for the input.
Internally it does the following code:
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

renderizablebody.

Returns

number x - 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)
_images/box_2d_getWorldCenter.png

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
  • renderizablebody.

  • numberx point on the body measured relative the the body’s origin.

  • numbery point on the body measured relative the the body’s origin.

Returns

number x - 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)
_images/box_2d_getWorldPoint.png

Figure 25.20 box2d getWorldPoint method

getWorldVector(tBody, number x, number y)

Get the world coordinates of a vector given the local coordinates.

Parameters
  • renderizablebody.

  • numberx local fixed in the body.

  • numbery local fixed in the body.

Returns

number x - 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)
_images/box_2d_getWorldVector.png

Figure 25.21 box2d getWorldVector method

getLocalPoint(tBody)

Gets a local point relative to the body’s origin given a world point.

Parameters
  • renderizablebody.

  • numberx world coordinates.

  • numbery world coordinates.

Returns

number x - 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

renderizablebody.

Returns

number x - 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, kinematic or dynamic.

Parameters
  • renderizablebody.

  • stringtype of body.

Example:

tPhysic:setType(tBody,'static')
getType(tBody)

Retrieve the body type.

The possible types are:static, kinematic or dynamic.

Parameters

renderizablebody.

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

renderizablebody.

Returns

number x - number - y the linear velocity of the center of mass.

Example:

local lx,ly = tPhysic:getLinearVelocity(tBody)
getAngularVelocity(tBody)

Get the angular velocity.

Parameters

renderizablebody.

Returns

number - angular velocity in radians/second.

Example:

local angular_velocity = tPhysic:getAngularVelocity(tBody)
setAngularVelocity(tBody, number omega)

Set the angular velocity.

Parameters
  • renderizablebody.

  • numberomega. 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
  • renderizablebody.

  • numberx. the new linear velocity of the center of mass.

  • numbery. 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

The engine accept two extras parameters to initialize the joint definition in box2d. (see b2DistanceJointDef::Initialize)
These parameters Initialize localAnchorA, localAnchorB and length.
You should consider the box2d scale for localAnchorA, localAnchorB, length, anchor1 and anchor2.

The extra parameters for this joint table are:
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

The engine accept one extra parameter to initialize the joint definition in box2d. (see b2FrictionJointDef::Initialize)
This parameter Initialize localAnchorA and localAnchorB.
You should consider the box2d scale for localAnchorA, localAnchorB, and anchor.

The extra parameter for this joint is described bellow:
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

The engine accept two extras parameters to initialize the joint definition in box2d. (see b2PrismaticJointDef::Initialize)
These parameters Initialize localAnchorA, localAnchorB and localAxisA.
You should consider the box2d scale for localAnchorA, localAnchorB, and anchor.

The extra parameters for this joint table are:
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

The engine accept extras parameters to initialize the joint definition in box2d. (see b2PulleyJointDef::Initialize)
These parameters Initialize localAnchorA, localAnchorB, groundAnchorA, groundAnchorB, lengthA and lengthB.
You should consider the box2d scale for localAnchorA, localAnchorB, groundAnchorA, groundAnchorB, lengthA and lengthB.

The extra parameters for this joint table are:
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.

The pulley connects two bodies to ground and to each other. As one body goes up, the other goes down.
The total length of the pulley rope is conserved according to the initial configuration: lengthA + lengthA == constant.
You can supply a ratio that simulates a block and tackle. This causes one side of the pulley to extend faster than the other.
At the same time the constraint force is smaller on one side than the other: lengthA + ratio * lengthB == constant

25.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:

  1. you might not know where the center of mass will be.

  2. 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

The engine accept one extra parameter to initialize the joint definition in box2d. (see b2RevoluteJointDef::Initialize)
This parameter Initialize localAnchorA, localAnchorB and referenceAngle.
You should consider the box2d scale for localAnchorA, localAnchorB and anchor.

The extra parameter for this joint is described bellow:
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

The engine accept one extra parameter to initialize the joint definition in box2d. (see b2WeldJointDef::Initialize)
This parameter Initialize localAnchorA, localAnchorB and referenceAngle.
You should consider the box2d scale for localAnchorA, localAnchorB, and anchor.

The extra parameter for this joint is described bellow:
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 line joint).

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

The engine accept two extras parameters to initialize the joint definition in box2d. (see b2WheelJointDef::Initialize)
These parameters Initialize localAnchorA, localAnchorB and localAxisA.
You should consider the box2d scale for localAnchorA, localAnchorB, and anchor.

The extra parameters for this joint table are:
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
  • renderizablefirst body.

  • renderizablesecond body.

  • tablejoint definition. see box2d joint

Returns

number - index absolute of joint. (zero is error).

Note

The result for this method is a number indicating the absolute index in the engine for this joint.
This absolute index can be invalid after destroying joint.
To get the joint use getJoint method and prefer to pass the absolute index.

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)
_images/box_2d_joint_distance.gif

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)
_images/box_2d_joint_friction.gif

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)
_images/box_2d_joint_gear.gif

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)
_images/box_2d_joint_motor.gif

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
_images/box_2d_joint_mouse.gif

Figure 25.26 Mouse joint

Note

Note that we are considering the box2d scale when we set the target through the method setTarget.
Also note that mouse joint take the same body in the first and second argument.

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
_images/box_2d_joint_prismatic.gif

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)
_images/box_2d_joint_pulley.gif

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)
_images/box_2d_joint_revolute.gif

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)
_images/box_2d_joint_rope.gif

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)
_images/box_2d_joint_weld.gif

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 loop(delta,fpsProp)
    tShapCar.tJointWheel1:setMotorSpeed(motorSpeed * direction_car)
    tShapCar.tJointWheel2:setMotorSpeed(motorSpeed * direction_car)
end
_images/box_2d_joint_wheel.gif

Figure 25.32 Wheel joint

25.3.3. Joint methods

Note

Not all joint has the same methods, each joint has its particularity.

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

booleanvalue - Set Active for both bodies

Example:

tJoint:setActive(true)

25.3.5. Angular offset options

getAngularOffset

Available for motor.

Returns

number - angular offset

Example:

local angular_offset = tJoint:getAngularOffset()
setAngularOffset(number angular_offset)

Available for motor.

Parameters

numberangular_offset.

Example:

local angular_offset = math.rad(10)
tJoint:setAngularOffset(angular_offset)

25.3.6. Anchor options

getAnchorA
Available for all joints
Get the anchor point on body ‘A’ in world coordinates.
return

number x - number - y anchor on body ‘A’ in world coordinates.

Example:

local x,y = tJoint:getAnchorA()
getAnchorB
Available for all joints
Get the anchor point on body ‘B’ in world coordinates.
return

number x - 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

numbercorrection 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

numberdamping ratio.

Example:

local damping_ratio = 2
tJoint:setDampingRatio(damping_ratio)

25.3.9. Destroy joint

destroyJoint(tBody)
Parameters

renderizablebody.

Example:

tPhysic:destroyJoint(tBody)

Note

The engine will destroy the joint in the next cycle.
destroyJoint is only available for box2d instance. It is not available for joint table.

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

numbermaximum 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

numberhertz.

Example:

local hertz = 30
tJoint:setFrequencyHz(hertz)
getFrequencyHz

Available for distance , wheel, weld .

Returns

number - hertz

Example:

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
  • renderizablebody.

  • numberabsolute index of the joint in the engine. (this index can be invalid after destroying joint).

Returns

table - joint

Example:

tJoint = tPhysic:getJoint(tBody,indexMyJoint)

Note

Retrieve a joint previously created using box2d instance.

25.3.13. Length options

getLength

Available for distance , rope .

Max length for rope .

Returns

number - length for distance or max length for rope .

Example:

local length = tJoint:getLength()
setLength

Available for distance , rope .

Max length for rope .

Parameters

numberlength for distance or max length for rope .

Example:

local length = 10
tJoint:setLength(length)

25.3.14. Limit options

enableLimit(boolean value)

Available for revolute, prismatic.

Parameters

booleanvalue.

Example:

local enable = true
tJoint:enableLimit(enable)
getLimits

Available for revolute, prismatic.

Returns

number lower - number - upper

Example:

local lower, upper = tJoint:getLimits()
setLimits(number lower, number upper)

Available for revolute, prismatic.

Parameters
  • numberlower.

  • numberupper.

Example:

local lower, upper = 10, 10
tJoint:setLimits(lower,upper)

25.3.15. Linear offset options

getLinearOffset

Available for motor.

Returns

number x - number - y (Frame A in Meters).

Example:

local x,y = tJoint:getLinearOffset()
setLinearOffset(number x, number y)

Available for motor

Parameters
  • numberx (Frame A in Meters).

  • numbery (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

numberspeed in radian per second.

Example:

local speed = math.rad(360)
tJoint:setMotorSpeed(speed)
getMaxMotorTorque

Available for revolute, wheel, motor

Returns

number - max motor torque

Example:

local max_torque = tJoint:getMaxMotorTorque()
setMaxMotorTorque(number max_torque)

Available for revolute, wheel, motor

Parameters

numbermax torque.

Example:

local torque = 5
tJoint:setMaxMotorTorque(torque)
enableMotor(boolean value)

Available for revolute, prismatic, wheel.

Parameters

booleanvalue.

Example:

local enable = true
tJoint:enableMotor(enable)

25.3.17. Reaction options

getReactionForce(number inv_delta)

Available for all joints

Parameters

numberinv_delta.

Returns

number x - 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

numberinv_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 2dw coordinates.
Returns

number x - 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
  • numberx.

  • numbery.

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

25.4. box2d LiquidFun

LiquidFun is a 2D rigid-body and fluid simulation C++ library for games based upon Box 2D . It provides support for procedural animation of physical bodies to make objects move and interact in realistic ways.

Discuss LiquidFun with other developers and users on the mailing list of LiquidFun.

Report issues on the issues tracker or post your questions to stackoverflow tagged with “liquidfun”.

Please take a look at LiquidFun Programmer’s Guide which is available for C++ but also applies to this wrapper over LUA

Some implementation in this wrapper is slightly different from the original version of C++. For example, is not available the manipulation of particle buffer directly through Lua.

Next one example of what can be done with this feature:

_images/fluid-showcase.gif

Figure 25.33 Fluid particle showcase

Attention

This engine implements LiquidFun under feature/liquid_fun and feature/liquidFun_box2d-2.4.1 branch.

25.4.1. LiquidFun createFluid

The implementation of LiquidFun is a bit different from others object in this engine.

First, a renderizable is not available for the fluid, therefore, you do not need to create a separated object which represent the fluid. All you need is to configure a texture plus some parameters and the fluid is created and the engine will take care of render it.

Two tables are the arguments needed for creating a fluid , initial physical format, and options.

Next is presented the table definition for the initial physical format (which could be an array as well):

type /
name
sub table
information
values
information

rectangle

center
width
height
{x, y, z}
value
value

triangle

a
b
c
{x, y, z}
{x, y, z}
{x, y, z}

circle

center
ray
{x, y, z}
value

e.g. single table:

{
    type    = 'rectangle',
    center  = {x=0,y=0,z=0},
    width   = 600,
    height  = 400,
}

{
    type    = 'circle',
    center  = {x=0,y=0,z=0},
    ray     = 200,
}

e.g. array table:

{
    {
        type    = 'rectangle',
        center  = {x=0,y=0,z=0},
        width   = 600,
        height  = 400,
    },

    {
        type    = 'circle',
        center  = {x=0,y=0,z=0},
        ray     = 200,
    }
}

And next is presented the definition for the options table:

identifier /
name
Type
value
Default
value
values
information

position

table

{x=0,y=0,z=0}

Initial position of the origin of center of particle

scale

table

{x=1,y=1}

Initial scale of particle system.
This reflect in the size of shape.
E.g.: shape circle ray=5
scale {x=2,y=2} => ray=10

color

table

{r=1,g=1,b=1,a=1}

Color to be applied to the fluid shader
If not present the shader will not contain particle on it

texture

string

#AAFF00FF

Path to the texture filename

is2dScreen

boolean

false

true The fluid is 2d Screen coordinate
false The fluid is 2d World coordinate

is3d

boolean

false

true The fluid is 3d World coordinate
false The fluid is 2d World/Screen coordinate

segmented

boolean

false

true The texture is mapped to the whole physics
false The texture is mapped to a single particle

radius

number

0.5

radius of each particle (physics)

radiusScale

number

1.0

1.0 means no scale.
This scale is only for the particle (not the physics)

damping

number

0.5

Reduces velocity along the collision normal
Smaller value reduces less

stride

number

0

The interval of particles in the shape.
If 0, 0.75 * particle diameter is used

strength

number

1.0

The strength of cohesion among the particles
in a group with flag elastic or spring

lifetime

number

0.0

Lifetime of the particle in seconds.
A value <= 0.0 indicates an infinite life time.

angle

number

0.0

The initial rotational angle of the particle.

angularVelocity

number

0.0

The initial angular velocity of particle

linearVelocity

table

{x=0,y=0}

Initial Linear velocity of particle system

blend

string

one

Blend options. See blend state

operation

string

add

Blend options. See blend operation

flags

string

water

Single flag or combined. See fluid flags

groupFlags

string

solidParticleGroup

Single group flag or combined. See fluid group flags

For the next examples, it will be used this texture:

_images/fluid_particle.png

Figure 25.34 Texture for fluid particle

download fluid_particle.png.

Example:

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
     {   type   = 'rectangle',
         center = {x=0,y=0,z=0},
         width  = 200, height = 400,
     },
     {   texture     ='fluid_particle.png',
         color       = {r = 0.0, g = 0.0, b =1.0},
         radiusScale = 2.0,
         flags       = "water",
         groupFlags  = {"solidParticleGroup"},
     })
_images/fluid-1.gif

Figure 25.35 Basic example fluid box2d:LiquidFun

Tip

In this example, we are appling the blue color to the particle.
The texture is used as reference to render (shape of particle).
The alpha is ignored because there is no alpha in the texture.

Example 2 no color:

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
     {   type   = 'rectangle',
         center = {x=0,y=0,z=0},
         width  = 200, height = 400,
     },
     {   texture     ='fluid_particle.png',
         radiusScale = 2.0,
         flags       = "water",
         groupFlags  = {"solidParticleGroup"},
     })
_images/fluid-2.gif

Figure 25.36 Basic example no color to texture fluid box2d:LiquidFun

Note

When no color is applied, there is no effect to color methods getColor/setColor anymore.

Example 3 array of physical shape:

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
 {
     {   type   = 'rectangle',
         center = {x=-50,y=0,z=0},
         width  = 50,
         height = 50,
     },
     {   type   = 'circle',
         center = {x=50,y=30,z=0},
         ray    = 50,
     },
 },
 {   texture     ='fluid_particle.png',
     flags       = "powder",
     groupFlags  = {"solidParticleGroup"},
 })
_images/fluid-array-of-shape-1.gif

Figure 25.37 Basic example array of shape

25.4.2. LiquidFun flags

The particle flag can be combined as array.

name
information

Compatible

water

Water particle

Yes

zombie

Removed after next simulation step

Yes

wall

Zero velocity

Yes

spring

With restitution from stretching

Yes

elastic

With restitution from deformation

Yes

viscous

With viscosity

Yes

powder

Without isotropic pressure

Yes

tensile

With surface tension

Yes

colorMixing

Mix color between contacting particles

No

destructionListener

Call b2DestructionListener on destruction

No

barrier

Prevents other particles from leaking

Yes

staticPressure

Less compressibility

Yes

reactive

Makes pairs or triads with other particles

Yes

repulsive

With high repulsive force

Yes

25.4.3. LiquidFun group flags

The particle group flag can be combined as array.

name
information

Compatible

solidParticleGroup

Prevents overlapping or leaking

Yes

rigidParticleGroup

Keeps its shape

Yes

particleGroupCanBeEmpty

Won’t be destroyed if it gets empty

Yes

particleGroupWillBeDestroyed

Will be destroyed on next simulation step

Yes

particleGroupNeedsUpdateDepth

Updates depth data on next simulation step

No

25.4.4. LiquidFun flags examples

To exemplify how to differ the flags, see the examples bellow:

For the fluid, we will use this texture:

_images/fluid_particle.png

Figure 25.38 Texture for fluid particle

Code:

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
     {   type   = 'rectangle',
         center = {x=0,y=0,z=0},
         width  = 200,
         height = 200,
     },
     {   texture     ='fluid_particle.png',
         flags       = "water",
         groupFlags  = {"solidParticleGroup"},
     })
_images/fluid-3.gif

Figure 25.39 Example flags “water”

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
     {   type   = 'rectangle',
         center = {x=0,y=0,z=0},
         width  = 200,
         height = 200,
     },
     {   texture     ='fluid_particle.png',
         flags       = {"water","staticPressure"},
         groupFlags  = {"solidParticleGroup"},
     })
_images/fluid-4.gif

Figure 25.40 Example flags “water|staticPressure”

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
     {   type   = 'rectangle',
         center = {x=0,y=0,z=0},
         width  = 200,
         height = 200,
     },
     {   texture     ='fluid_particle.png',
         flags       = "elastic",
         groupFlags  = {"solidParticleGroup"},
     })
_images/fluid-5.gif

Figure 25.41 Example flags “elastic”

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
     {   type   = 'rectangle',
         center = {x=0,y=0,z=0},
         width  = 200,
         height = 200,
     },
     {   texture     ='fluid_particle.png',
         flags       = "viscous",
         groupFlags  = {"solidParticleGroup"},
     })
_images/fluid-6.gif

Figure 25.42 Example flags “viscous”

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
     {   type   = 'rectangle',
         center = {x=0,y=0,z=0},
         width  = 200,
         height = 200,
     },
     {   texture     ='fluid_particle.png',
         flags       = "powder",
         groupFlags  = {"solidParticleGroup"},
     })
_images/fluid-7.gif

Figure 25.43 Example flags “powder”

25.5. LiquidFun methods

25.5.1. LiquidFun add particles

add(table shape, table infoPosScale)
Add particles given the shape. See initial physical format.

Info position and scale is defined as:
field
Information
x
y
z
sx
sy
sz
Position x
Position y
Position z
Scale x
Scale y
Scale z
Parameters
  • tableshape physical format.

  • tableinfo position and scale.

Returns

number particles added.

Example:

 require "box2d"
 mbm.setColor(0.6,0.6,0.6)

 tPhysic = box2d:new()

 tShapeGround    = shape:new('2dw',0,-200)
 tShapeLeftWall  = shape:new('2dw',-200,0)
 tShapeRightWall = shape:new('2dw',200,0)
 tShapeUpWall    = shape:new('2dw',0,200)

 tShapeGround:create('rectangle',400,20)
 tShapeRightWall:create('rectangle',20,400)
 tShapeLeftWall:create('rectangle',20,400)
 tShapeUpWall:create('rectangle',400,20)

 tPhysic:addStaticBody(tShapeGround)
 tPhysic:addStaticBody(tShapeRightWall)
 tPhysic:addStaticBody(tShapeLeftWall)
 tPhysic:addStaticBody(tShapeUpWall)

 tFluid = tPhysic:createFluid(
     {   type   = 'rectangle',
         center = {x=0,y=0,z=0},
         width  = 200,
         height = 200,
     },
     {   texture     ='fluid_particle.png',
         flags       = "powder",
         groupFlags  = {"solidParticleGroup"},
     })


 function onTouchDown(key,x,y)
     local x,y = mbm.to2dw(x,y)
     local tCircle =
     {
         type = 'circle',
         ray  = 20,
     }
     local infoPosScale =
     {
         x = x,
         y = y,
         sx = 1,
         sy = 1,
     }
     local iTotalParticleAdded = tFluid:add(tCircle,infoPosScale)
     print('Total particle added:',iTotalParticleAdded)

 end
_images/fluid-add-particle-shape.gif

Figure 25.44 Example adding particle

25.5.2. LiquidFun particle count

getParticleCount

Get the number of particles.

return

number particles count.

Example:

 local iTotalParticle = tFluid:getParticleCount()
 print(iTotalParticle)
getMaxParticleCount

Get the maximum number of particles.

Returns

number maximum number of particles.

Example:

 local iMaxParticle = tFluid:getMaxParticleCount()
 print(iMaxParticle)
setMaxParticleCount(number max)
Set the maximum number of particles.
By default, there is no maximum. The particle buffers can continue to
grow while b2World’s block allocator still has memory.
Parameters

numbermax maximum number of particles.

Example:

 tFluid:setMaxParticleCount(500)

25.5.3. LiquidFun particle color

getColor
Get the particle’s color.
It only has effect when created with color option.
Returns

number red, number green, number blue, number alpha - color of fluid.

Example:

local r,g,b,a = tFluid:getColor()
setColor(number red, number green, number blue, number * alpha)
Set the particle’s color.
It only has effect when created with color option.
Parameters
  • numberred color.

  • numbergreen color.

  • numberblue color.

  • numberalpha color (optional).

Example:

local r,g,b,a = 1.0, 0.4, 0.3, 0.9
tFluid:setColor(r,g,b,a)
setColor(table color)
Set the particle’s color.
It only has effect when created with color option.
Parameters

tablecolor {r,g,b,a}.

Example:

local tColor = {r=1.0, g=1.0, b=0.4, a=0.3}
tFluid:setColor(tColor)

25.5.4. LiquidFun particle pause

setPaused(boolean paused)
Pause or unpause the particle system.
When paused, b2World::Step() skips over this particle system.
All b2ParticleSystem function calls still work.
Parameters

booleanpaused value.

Example:

tFluid:setPaused(true)

25.5.5. LiquidFun particle density

getDensity
Get the particle density.
Returns

number density

Example:

local density = tFluid:getDensity()
setDensity(number density)
Change the particle density.
Particle density affects the mass of the particles, which in turn
affects how the particles interact with b2Bodies. Note that the density
does not affect how the particles interact with each other.
Parameters

numberdensity

Example:

local density = tFluid:getDensity()
tFluid:setDensity(density * 2.0)

25.5.6. LiquidFun particle gravity scale

getGravityScale
Get the particle gravity scale.
Returns

number gravity scale

Example:

local gravity_scale = tFluid:getGravityScale()
setGravityScale(number gravity_scale)
Change the particle gravity scale.
Adjusts the effect of the global gravity vector on particles.
Parameters

numbergravity scale

Example:

local gravity_scale = tFluid:getGravityScale()
tFluid:setGravityScale(gravity_scale * 2.0)

25.5.7. LiquidFun particle damping

getDamping
Get damping for particles
Returns

number damping

Example:

local damping = tFluid:getDamping()
setDamping(number damping)
Damping is used to reduce the velocity of particles.
The damping parameter can be larger than 1.0 but the damping
effect becomes sensitive to the time step when the damping parameter is large.
Parameters

numberdamping

Example:

tFluid:setDamping(0.5)

25.5.8. LiquidFun particle static pressure

Change the number of iterations when calculating the static pressure of
particles. By default, 8 iterations. You can reduce the number of
iterations down to 1 in some situations, but this may cause
instabilities when many particles come together. If you see particles
popping away from each other like popcorn, you may have to increase the
number of iterations.
For a description of static pressure, see
getStaticPressureIterations
Get the number of iterations for static pressure of particles.
Returns

number iterations for static pressure of particles

Example:

local iterations = tFluid:getStaticPressureIterations()
setStaticPressureIterations(number iterations)
Parameters

numberiterations

Example:

tFluid:setStaticPressureIterations(3)

25.5.9. LiquidFun particle radius

The radius is defined in the moment of creation of fluid.
getRadius
Get the particle radius.
Returns

number particle radius

Example:

local radius = tFluid:getRadius()

25.5.10. LiquidFun particle life time

All particules are created with 0.0 lifetime (infinite lifetime).
A value > 0.0 is returned if the particle is scheduled to be
destroyed in the future, values <= 0.0 indicate the particle has an
infinite lifetime.
getParticleLifetime(number index)
Get the lifetime (in seconds) of a particle relative to the current time.
Parameters

numberindex of particle (1 based).

Returns

number lifetime

Example:

local index = 1 -- first particle in the system
local lifetime = tFluid:getParticleLifetime(index)
setParticleLifetime(number index, number lifetime)
Set the lifetime (in seconds) of a particle relative to the current time.
A lifetime of less than or equal to 0.0f results in the particle
living forever until it’s manually destroyed by the application.
Parameters
  • numberindex of particle (1 based).

  • numberlifetime of particle in seconds.

Example:

local index = 1 -- first particle in the system
local lifetime = 2.0
tFluid:setParticleLifetime(index,lifetime)

25.5.11. LiquidFun destroy particles

destroyParticle(number index)
Destroy a particle.
The particle is removed after the next simulation step (see b2World::Step()).
Parameters

numberindex of particle (1 based).

Example:

local index = 1 -- first particle in the system
tFluid:destroyParticle(index)
destroyParticlesInShape(table shape)
Destroy particles inside a shape without enabling the destruction callback for destroyed particles.
This function is locked during callbacks.
For more information see DestroyParticleInShape(const b2Shape&, const b2Transform&,bool).
Parameters

tableshape which encloses particles that should be destroyed.

Example:

 local tShapeRect     = {type   = 'rectangle',
                         width  = 100,
                         height = 100,
                         x = 0, y =0, angle = 0}
 tFluid:destroyParticlesInShape(tShapeRect)

 local tShapeCircle   = {type = 'circle',
                         ray  = 30,
                         x = 0, y =0, angle = 0}
 tFluid:destroyParticlesInShape(tShapeCircle)

 local tShapeTriangle = {type = 'triangle',
                         a = {x = -20, y = -20},
                         b = {x =  20, y = -20},
                         c = {x =  20, y =  20},
                         x = 0, y =0, angle = 0}
 tFluid:destroyParticlesInShape(tShapeTriangle)

Note

The position x, y and the angle are available for any type of shape.

destroyParticlesInShape(renderizable body)
Destroy particles inside a shape without enabling the destruction callback for destroyed particles.
This function is locked during callbacks.
For more information see DestroyParticleInShape(const b2Shape&, const b2Transform&,bool).
Parameters

renderizablebody which encloses particles that should be destroyed.

Example:

local tObj -- previously loaded
tFluid:destroyParticlesInShape(tObj)

25.5.12. LiquidFun particles impulse

particleApplyLinearImpulse([table | array] tImpulse)
Apply an impulse to one particle. This immediately modifies the velocity. Similar to b2Body::applyLinearImpulse.
Parameters

table{x,y,index} the impulse info for each particle (or array).

Example:

local tImpulse = {x = 100, y = 25, index = 1}
tFluid:particleApplyLinearImpulse(tImpulse)

local tArraysImpulse = {{x = 100, y = 25, index = 1},{x = 100, y = 25, index = 2},{x = 100, y = 25, index = 3}}
tFluid:particleApplyLinearImpulse(tArraysImpulse)
applyLinearImpulse(number firstIndex, number lastIndex, number x, number y)
Apply an impulse to all particles between ‘firstIndex’ and ‘lastIndex’.
This immediately modifies the velocity.
Note that the impulse is applied to the total mass of all particles. So,
calling particleApplyLinearImpulse(0, impulse) and particleApplyLinearImpulse(1, impulse)
will impart twice as much velocity as calling just applyLinearImpulse(0, 1, impulse).
Parameters
  • numberfirstIndex (1 based)

  • numberlastIndex (1 based)

  • numberx impulse

  • numbery impulse

Example:

local firstIndex = 1
local lastIndex  = 250
local x,y = 100, 25
tFluid:applyLinearImpulse(firstIndex,lastIndex,x,y)

25.5.13. LiquidFun particles force

particleApplyForce([table | array] tForce)
Apply a force to the center of a particle.
The world force vector is usually in Newtons (N).
Parameters

table{x,y,index} the force info for each particle (or array).

Example:

local tForce = {x = 50, y = 33, index = 1}
tFluid:particleApplyForce(tForce)

local tArrayForce = {{x = 50, y = 33, index = 1},{x = 50, y = 33, index = 2},{x = 50, y = 33, index = 3}}
tFluid:particleApplyForce(tArrayForce)
applyForce(number firstIndex, number lastIndex, number x, number y)
Distribute a force across several particles.
The particles must not be wall particles.
Note that the force is distributed across all the particles, so calling
this function for indices 0..N is not the same as
calling particleApplyForce(i, force) for i in 0..N.
Parameters
  • numberfirstIndex (1 based)

  • numberlastIndex (1 based)

  • numberx force

  • numbery force

Example:

local firstIndex = 1
local lastIndex  = 300
local fx,fy = 50, 33
tFluid:applyForce(firstIndex,lastIndex,fx,fy)

25.5.14. LiquidFun particles colision

queryAABB(number lowerBound_x, number lowerBound_y, number upperBound_x, number upperBound_y, function onQueryAABBB)

Perform a AABB algorithm collision for all objects given the bound.

It considers box2d scale.

The callback is called in case of collision.

It has to have the following signature:

function onQueryAABBB(tFluid, indexParticle)

end

Example:

-- TODO
queryShapeAABB(table shape, function onQueryShapeAABB)

Perform a AABB algorithm collision for all objects given the shape.

It considers box2d scale.

The callback is called in case of collision.

It has to have the following signature:

function onQueryShapeAABB(tFluid, indexParticle)

end

The shape is defined as:

type /
name
field
name
values
information

rectangle

width
height
x
y
angle
value
value
x position
y position
radian

triangle

a
b
c
x
y
angle
{x, y}
{x, y}
{x, y}
x position
y position
radian

circle

ray
x
y
angle
value
x position
y position
radian

Example:

-- TODO
queryShapeAABB(table renderizable, function onQueryShapeAABB)

Perform a AABB algorithm collision for all objects given the renderizable.

It considers box2d scale.

The callback is called in case of collision.

It has to have the following signature:

function onQueryShapeAABB(tFluid, indexParticle)

end

Example:

-- TODO

25.5.15. LiquidFun particles compute bounds

computeAABB(number lowerBound_x, number lowerBound_y, number upperBound_x, number upperBound_y)
Compute the axis-aligned bounding box for all particles contained within this particle system.
Returns the axis-aligned bounding box of the system.
Parameters
  • numberlowerBound_x

  • numberlowerBound_y

  • numberupperBound_x

  • numberupperBound_y

Returns

table {lowerBound = {x,y},upperBound = {x,y}}

Example:

local lowerBound_x = 0
local lowerBound_y = 0
local upperBound_x = 100
local upperBound_y = 100
local tBound = tFluid:computeAABB(lowerBound_x,lowerBound_y,upperBound_x,upperBound_y)
print(tBound.lowerBound.x)
print(tBound.lowerBound.y)
print(tBound.upperBound.x)
print(tBound.upperBound.y)

25.5.16. LiquidFun particles ray cast

rayCast(number x_start, number y_start, number x_end, number y_end, function onRayCastCallBack)
Parameters
  • numberx start point of the ray-cast.

  • numbery start point of the ray-cast.

  • numberx end point of the ray-cast.

  • numbery end point of the ray-cast.

  • functioncall back function ray-cast.

It considers box2d scale.

--Ray cast callback
function onRayCast(index,x,y,nx,ny,fraction)

    message = string.format('Particle: %d, at x:%g y:%g   normal nx:%g ny:%g    fraction:%g',index,x,y,nx,ny,fraction)
    print(message)
    return fraction --if you return 0 it means end of ray-cast
end

25.5.17. LiquidFun getVersion

getVersion

Get the current version of box2d + LiquidFun.

Example:

 require "box2d"
 version = box2d:getVersion()
 print(version)

The output will be “x.x.x” for the box2d version followed by LiquidFun x.x.x version.

e.g.: 2.3.0 LiquidFun 1.1.0