.. contents:: Table of Contents .. _box2d: 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 :ref:`box2d ` can be found :ref:`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 :ref:`scale factor `. | Always use function from :ref:`box2d ` when related to position (locations). | E.g: Prefer to use :ref:`box2d:getPosition ` instead of the position of :ref:`renderizable:getPosition `. | When transforming from :ref:`2d world ` to :ref:`box2d ` consider :ref:`box2d scale ` | Example: .. code-block:: lua 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 box2d Methods ------------- box2d getVersion ^^^^^^^^^^^^^^^^ .. data:: getVersion() :noindex: Get the current version of :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 2 require "box2d" version = box2d:getVersion() print(version) box2d new ^^^^^^^^^ .. data:: new(number * gravity_x, number * gravity_y number * scale_box_2d, number * velocityIterations, number * positionIterations, number * multiplyStep) :noindex: Create a new instance of a :ref:`box2d `. :param number: **gravity** in the axis x, default is ``0.0``. :param number: **gravity** in the axis y, default is ``-90.8``. :param number: **scale to apply in the world** default is ``10``. :param number: **velocity iterations** default is ``10``. :param number: **position iterations** default is ``3``. :param number: **multiply step** default is ``1``. :return: :ref:`box2d ` *table*. *Example:* .. code-block:: lua :emphasize-lines: 9 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()) .. figure:: _static/box_2d_example_1.png :align: center :figclass: align-center Creating box2d instance *Other example:* .. code-block:: lua :emphasize-lines: 2 require "box2d" tPhysic = box2d:new() --no arguments needed (same as before) print('Gravity :', tPhysic:getGravity()) print('Scale :', tPhysic:getScale()) print('Velocity iteration :', tPhysic:getVelocityIterations()) print('Position iteration :', tPhysic:getPositionIterations()) print('Multiply step :', tPhysic:getMultiply()) .. figure:: _static/box_2d_example_2.png :align: center :figclass: align-center Creating box2d instance without arguments 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 :guilabel:`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: .. code-block:: lua function onBeginContact(tMesh_a, tMesh_b) end :EndContact: Called when two fixtures cease to touch. It has the following signature: .. code-block:: lua 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: .. code-block:: lua 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 :guilabel:`EndContact` callback. However, you may get a :guilabel:`BeginContact` callback the next step. .. Note:: :guilabel:`b2Manifold` from `Box 2D `__ has more member in the structure then :ref:`this `. The engine omit them. See :ref:`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: .. code-block:: lua function onPostSolve(tMesh_a, tMesh_b, tImpulse) end .. Note:: | This is only called for contacts that are touching, solid, and awake. The :guilabel:`b2ContactImpulse` used by the engine has the following members: .. code-block:: lua tImpulse = { count = 0, normalImpulses = {[1] = 0, [2] = 0}, tangentImpulses = {[1] = 0, [2] = 0}} .. data:: setContactListener(function onBeginContact,function onEndContact,function onPreSolve,function onPostSolve) :param function: **onBeginContact** callback (may be ``nil``). :param function: **onEndContact** callback (may be ``nil``). :param function: **onPreSolve** callback (may be ``nil``). :param function: **onPostSolve** callback (may be ``nil``). *Example:* .. code-block:: lua require "box2d" function print_manifold(tManifold) print('type:',tManifold.type) print('pointCount:',tManifold.pointCount) print('localNormal.x:',tManifold.localNormal.x) print('localNormal.x:',tManifold.localNormal.y) print('localPoint.x:',tManifold.localPoint.x) print('localPoint.x:',tManifold.localPoint.y) for i =1, #tManifold.points do print('point:',i) print('\tlocalPoint.x:',tManifold.points[1].localPoint.x) print('\tlocalPoint.y:',tManifold.points[1].localPoint.y) print('\tnormalImpulse:',tManifold.points[1].normalImpulse) print('\ttangentImpulse:',tManifold.points[1].tangentImpulse) end print('\n') end -- Callbacks function onBeginContact(tMesh_a, tMesh_b) print('\n') print('Begin contact:') print('Collision:',tMesh_a.name,tMesh_b.name) end function onEndContact(tMesh_a, tMesh_b) print('\n') print('End contact:') print('Collision:',tMesh_a.name,tMesh_b.name) end function onPreSolve(tMesh_a, tMesh_b, tManifold) print('\n') print('onPreSolve:') print('Collision:',tMesh_a.name,tMesh_b.name) print_manifold(tManifold) end function onPostSolve(tMesh_a, tMesh_b, tImpulse) print('\n') print('Impulse:') print('Impulse.count:', tImpulse.count) print('Impulse.normalImpulses[1]:', tImpulse.normalImpulses[1]) print('Impulse.normalImpulses[2]:', tImpulse.normalImpulses[2]) print('Impulse.tangentImpulses[1]:', tImpulse.tangentImpulses[1]) print('Impulse.tangentImpulses[2]:', tImpulse.tangentImpulses[2]) end -- End callbacks mbm.setColor(1,1,1) --set background color to white tPhysic = box2d:new() tShapeQuad = shape:new('2dw',-10, 500) tShapeCircle = shape:new('2dw',50 , 300) tShapeGround = shape:new('2dw',0,-50) tShapeBigCircle = shape:new('2dw',200,800) tShapeQuad.name = 'rectangle' tShapeCircle.name = 'circle' tShapeBigCircle.name = 'big circle' tShapeGround.name = 'ground' tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeBigCircle:create('circle',200,200) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeBigCircle) tPhysic:addStaticBody(tShapeGround) tPhysic:setContactListener(onBeginContact,onEndContact,onPreSolve,onPostSolve) camera = mbm.getCamera('2d') camera.y = 300 .. figure:: _static/box_2d_set_contact_listener.gif :align: center :figclass: align-center Example setContactListener box2d box2d gravity ^^^^^^^^^^^^^ .. data:: getGravity() Return gravity used by :ref:`box2d `. :return: ``number`` *gravity x*, ``number`` *gravity y* - of :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() print('Gravity :', tPhysic:getGravity()) .. data:: setGravity(number gravity_x, number gravity_y) Set a new gravity to :ref:`box2d `. :param number: **gravity** in the axis x. :param number: **gravity** in the axis y. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() tPhysic:setGravity(-3,95.8) box2d iterations ^^^^^^^^^^^^^^^^ .. data:: getVelocityIterations() Return the velocity iterations used by :ref:`box2d `. :return: ``number`` *velocity iterations* - of :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() print('Velocity iteration :', tPhysic:getVelocityIterations()) .. data:: getPositionIterations() Return the position iterations used by :ref:`box2d `. :return: ``number`` *position iterations* - of :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() print('Velocity iteration :', tPhysic:getPositionIterations()) .. _box2d_manifold: box2d manifold ^^^^^^^^^^^^^^ *A manifold table has the following structure:* .. code-block:: lua 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 }, } .. data:: getManifolds(tBody, boolean * checkIsTouching, boolean * checkIsEnabled) :param renderizable: **body**. :param boolean: **checkIsTouching** instruct to check :guilabel:`b2Contact::IsTouching()` from Box2d (default if ``false``). :param boolean: **checkIsEnabled** instruct to check :guilabel:`b2Contact::IsEnabled()` from Box2d (default if ``false``). :return: ``table`` - *manifold* array. *Example:* .. code-block:: lua --this is not a real example function print_manifold(tManifold) print('type:', tManifold.type) print('pointCount:', tManifold.pointCount) print('localNormal.x:', tManifold.localNormal.x) print('localNormal.x:', tManifold.localNormal.y) print('localPoint.x:', tManifold.localPoint.x) print('localPoint.x:', tManifold.localPoint.y) for i =1, #tManifold.points do print('point:', i) print('\tlocalPoint.x:', tManifold.points[1].localPoint.x) print('\tlocalPoint.y:', tManifold.points[1].localPoint.y) print('\tnormalImpulse:', tManifold.points[1].normalImpulse) print('\ttangentImpulse:', tManifold.points[1].tangentImpulse) end print('\n') end --when is colliding otherwise will not have manifold. local tManifolds = tPhysic:getManifolds(tMesh_a) for i =1, #tManifolds do print('\n') print('Manifold index:',i) print_manifold(tManifolds[i]) end .. figure:: _static/box_2d_manifold.png :align: center :figclass: align-center Example of output printing manifold structure. .. data:: setManifolds(tManifolds) :param table: **manifolds** previously got using :guilabel:`getManifolds` method. *Example:* .. code-block:: lua 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. box2d world manifold ^^^^^^^^^^^^^^^^^^^^ *A manifold world table has the following structure:* .. code-block:: lua tWorldManifold = { normal = {x = 0, y = 0 }, separations = [1] = 0, [2] = 0, points = {[1] = {x = 0, y = 0}, [2] = {x = 0, y = 0}} .. data:: getWorldManifold(tBody) :param renderizable: **body**. :return: ``table`` - *world manifold* array. *Example:* .. code-block:: lua require "box2d" function print_manifold_world(tWorldManifold) print('normal.x:',tWorldManifold.normal.x) print('normal.x:',tWorldManifold.normal.y) print('separations[1]:',tWorldManifold.separations[1]) print('separations[2]:',tWorldManifold.separations[2]) for i =1, #tWorldManifold.points do print('point:',i) print('\tx:',tWorldManifold.points[1].x) print('\ty:',tWorldManifold.points[1].y) end print('\n') end -- Callbacks function onPreSolve(tMesh_a, tMesh_b, tManifold) local tWorldManifolds = tPhysic:getWorldManifolds(tMesh_a) for i =1, #tWorldManifolds do print('WorldManifold index ', i) print_manifold_world(tWorldManifolds[i]) end end -- End callbacks mbm.setColor(1,1,1) --set background color to white tPhysic = box2d:new() tShapeQuad = shape:new('2dw',-10, 500) tShapeCircle = shape:new('2dw',50 , 300) tShapeGround = shape:new('2dw',0,-50) tShapeBigCircle = shape:new('2dw',200,800) tShapeQuad.name = 'rectangle' tShapeCircle.name = 'circle' tShapeBigCircle.name = 'big circle' tShapeGround.name = 'ground' tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeBigCircle:create('circle',200,200) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeBigCircle) tPhysic:addStaticBody(tShapeGround) tPhysic:setContactListener(nil,nil,onPreSolve,nil) camera = mbm.getCamera('2d') camera.y = 300 .. figure:: _static/box_2d_world_manifold.gif :align: center :figclass: align-center Example of accessing world manifold box2d multiply ^^^^^^^^^^^^^^ | `Box 2D `__ has a internal function which is called every step. This function is :guilabel:`b2World::Step`. | The first argument is :guilabel:`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: .. code-block:: C world->Step(delta * multiplyStep, velocityIterations, positionIterations); .. data:: getMultiply() Return the multiply step used by :ref:`box2d `. :return: ``number`` *multiply step* - of :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() print('Multiply step :', tPhysic:getMultiply()) .. data:: setMultiply(number multiply_step) Set a new multiply step to :ref:`box2d `. :param number: **multiply step** to the :ref:`box2d `, default is ``1.0``. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() tPhysic:setMultiply(2) .. _box2d_Scale: 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: .. code-block:: c++ 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: .. code-block:: c++ 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 :ref:`box2d `. It means that if you suspect that this scale is interfering in yours result then just set it to ``1``. .. data:: getScale() Return the scale used by :ref:`box2d `. :return: ``number`` *scale* - of :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() print('Scale :', tPhysic:getScale()) .. data:: setScale(number scale) Set a new scale to :ref:`box2d `. :param number: **scale** to the :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() tPhysic:setScale(20) box2d pause ^^^^^^^^^^^ .. data:: pause() :noindex: Pause the simulation of :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() tPhysic:pause() 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 :ref:`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. .. figure:: _static/box_2d_raycast_fraction.png :align: center :figclass: align-center 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: .. code-block:: lua 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 :ref:`box2d ` .. data:: rayCast(number x_start,number y_start, number x_end,number y_end,function onRayCastCallBack) :noindex: :param number: **x** start point of the ray-cast. :param number: **y** start point of the ray-cast. :param number: **x** end point of the ray-cast. :param number: **y** end point of the ray-cast. :param function: **call back** function ray-cast. It considers :ref:`box2d ` :ref:`scale `. *Example:* .. code-block:: lua :emphasize-lines: 3,55 require "box2d" --Ray cast callback function onRayCast(tMesh,x,y,nx,ny,fraction) message = string.format('Crossed line: %s, at x:%g y:%g normal nx:%g ny:%g fraction:%g',tMesh.name,x,y,nx,ny,fraction) print(message) tMesh:setColor(0.7,0,0) tShapePoint:setPos(x,y) tShapePoint.visible = true return fraction --if you return 0 it means end of ray-cast end mbm.setColor(1,1,1) --set background color to white local gravity_x = 0 local gravity_y = -9.8 --very slow to be able to see tPhysic = box2d:new(gravity_x,gravity_y) line_start = {x = -300, y = 200} line_end = {x = 300, y = 50} tLine = line:new('2dw') tLine:add({line_start.x,line_start.y,line_end.x,line_end.y}) tLine:setColor(0,0,1) -- Blue color tShapeQuad = shape:new('2dw',-20, 500) tShapeCircle = shape:new('2dw',50 , 300) tShapeGround = shape:new('2dw',0,-50) tShapePoint = shape:new('2dw') tShapeQuad.name = 'rectangle' tShapeCircle.name = 'circle' tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapePoint:create('circle',20,20) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addStaticBody(tShapeGround) function onLoop(delta,fps) tShapeQuad:setColor(0.7,0,0.7) --reset the shape's color tShapeCircle:setColor(0.7,0,0.7) --reset the shape's color tShapePoint.visible = false local pStart = {x = line_start.x , y = line_start.y } local pEnd = {x = line_end.x , y = line_end.y } tPhysic:rayCast(pStart.x,pStart.y,pEnd.x,pEnd.y,onRayCast) end .. figure:: _static/box_2d_raycast.gif :align: center :figclass: align-center Performing ray cast box2d box2d start ^^^^^^^^^^^ .. data:: start() Start or resume the simulation of :ref:`box2d `. *Example:* .. code-block:: lua :emphasize-lines: 3 require "box2d" tPhysic = box2d:new() tPhysic:start() --resume the simulation box2d queryAABB ^^^^^^^^^^^^^^^ .. data:: queryAABB(number lowerBound_x,number lowerBound_y,number upperBound_x,number upperBound_y,function onQueryAABBBox2d) :noindex: Perform a AABB algorithm collision for all objects given the bound. It considers :ref:`box2d ` :ref:`scale `. The callback is called in case of collision. It has to have the following signature: .. code-block:: lua function onQueryAABBBox2d(tMesh) end *Example:* .. code-block:: lua :emphasize-lines: 4,47 require "box2d" mbm.setColor(1,1,1) --set background color to white function onQueryAABBBox2d(tMesh) print('Collide with:',tMesh.name) if tMesh.name == 'circle' then tLine:setColor(1,0,0) -- red for circle elseif tMesh.name == 'rectangle' then tLine:setColor(0,0,1) --blue for rectangle end end local gravity_x = 0 local gravity_y = -9.8 --very slow to be able to see tPhysic = box2d:new(gravity_x,gravity_y) local lowerBound = {x = 0, y = 0} local upperBound = {x = 100, y = 100} tLine = line:new('2dw') tLine:add( {lowerBound.x,lowerBound.y, lowerBound.x,upperBound.y, upperBound.x,upperBound.y, upperBound.x,lowerBound.y, lowerBound.x,lowerBound.y}) tLine:setColor(1,1,1) --white color means no colision tShapeQuad = shape:new('2dw',-20, 500) tShapeCircle = shape:new('2dw',50 , 300) tShapeGround = shape:new('2dw',0,-50) tShapeQuad.name = 'rectangle' tShapeCircle.name = 'circle' tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeGround:create('rectangle',500,20) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addStaticBody(tShapeGround) function onLoop(delta) tPhysic:queryAABB(lowerBound.x,lowerBound.y,upperBound.x,upperBound.y,onQueryAABBBox2d) end .. figure:: _static/box_2d_example_query_AABB.gif :align: center :figclass: align-center Performing query AABB colision .. _body_box2d: 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 :ref:`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 :ref:`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 :ref:`box2d `: ``static``, ``dynamic`` and ``kinematic``. The engine implement them all. Any :ref:`renderizable ` object can be added to :ref:`box2d ` to be simulated with its physics properties, however, it makes sense for ``2D`` objects. The :ref:`body ` is based on physics properties which can be modified through :ref:`setPhysics ` from :ref:`meshDebug ` object. Bullet body ^^^^^^^^^^^ .. data:: setBullet(tBody, boolean value) Should this body be treated like a bullet for continuous collision detection? :param renderizable: **body**. :param boolean: **value**. *Example:* .. code-block:: lua tPhysic:setBullet(tBody,true) Character body ^^^^^^^^^^^^^^ A Character body is a dynamic body but using fixed rotation and do not allowing to sleep. Let's see an example: .. code-block:: lua :emphasize-lines: 28,29 require "box2d" mbm.setColor(1,1,1) --set background color to white local gravity_x = 0 local gravity_y = -9.8 --very slow to be able to see tPhysic = box2d:new(gravity_x,gravity_y) tShapeQuad = shape:new('2dw',-310, 50) tShapeCircle = shape:new('2dw', 0, 300) tShapeTriangle = shape:new('2dw', 50, 500) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) local density, friction, restitution = 1, 10, 0.8 -- restitution 0.1 -> 0.8 (super) tPhysic:addDynamicBody(tShapeCircle,density, friction, restitution) tPhysic:addKinematicBody(tShapeQuad) tPhysic:setLinearVelocity(tShapeQuad,2,0) -- move right 2 unit per second tPhysic:addDynamicBody(tShapeTriangle) tPhysic:setFixedRotation(tShapeTriangle,true) tPhysic:setSleepingAllowed(tShapeTriangle,false) tPhysic:addStaticBody(tShapeGround) .. figure:: _static/box_2d_example_character_body.gif :align: center :figclass: align-center Creating character body Damping options body ^^^^^^^^^^^^^^^^^^^^ .. data:: setAngularDamping(tBody, number angular_damping) :param renderizable: **body**. :param number: **angular damping**. *Example:* .. code-block:: lua tPhysic:setAngularDamping(tBody,15) Density option body ^^^^^^^^^^^^^^^^^^^ .. data:: setDensity(tBody,number density, boolean * reset_mass) :noindex: Set the density of all fixtures in the body. The optional flag reset_mass instruct to call :guilabel:`b2Body::ResetMassData` to update the body's mass. :param renderizable: **body**. :param number: **density**. :param boolean: **reset mass** flag, default is ``true``. *Example:* .. code-block:: lua tPhysic:setDensity(tBody,10,true) Destroy body ^^^^^^^^^^^^ .. data:: destroyBody(tBody) :param renderizable: **body**. *Example:* .. code-block:: lua tPhysic:destroyBody(tBody) .. Note:: The engine will destroy the body in the next cycle. Dynamic body ^^^^^^^^^^^^ Dynamic body can move, spin and also be influenced by the gravity. .. data:: addDynamicBody(renderizable mesh, number * density, number * friction, number * restitution, number * reduceX, number * reduceY, boolean * isSensor, boolean * isBullet) Create a new instance of a ``dynamic`` :ref:`body `. :param renderizable: any type of :ref:`mesh ` previouslly loaded according. :param number: **density** default is ``1.0``. :param number: **friction** default is ``10.0``. :param number: **restitution** default is ``0.1``. :param number: **scale** of reduction on ``x`` axis. default is ``1.0`` (real size). :param number: **scale** of reduction on ``y`` axis. default is ``1.0`` (real size). :param boolean: **sensor** flag (``true`` or ``false``) default is ``false``. :param boolean: **bullet** flag (``true`` or ``false``) default is ``false``. :return: :ref:`body ` *table*. *For this example let's create differents types of dynamic bodies:* .. code-block:: lua :emphasize-lines: 22, 25, 27 require "box2d" mbm.setColor(1,1,1) local gravity_x = 0 local gravity_y = -9.8 --very slow to be able to see tPhysic = box2d:new(gravity_x,gravity_y) tShapeQuad = shape:new('2dw',-100, 720) tShapeCircle = shape:new('2dw', 0, 500) tShapeTriangle = shape:new('2dw', 50, 300) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) local density, friction, restitution = 1, 10, 0.8 -- restitution 0.1 -> 0.8 (super) tPhysic:addDynamicBody(tShapeCircle,density, friction, restitution) density = 10 tPhysic:addDynamicBody(tShapeQuad,density) --heavy tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) .. figure:: _static/box_2d_example_creating_dynamic_body.gif :align: center :figclass: align-center Creating three dynamic bodies Filter options body ^^^^^^^^^^^^^^^^^^^ .. data:: setEnable(tBody, boolean value) Disable or enable a body changing internally the flag maskBits for each fixture in the body. :param renderizable: **body**. :param boolean: **value**. *Example:* .. code-block:: lua :emphasize-lines: 28 require "box2d" mbm.setColor(1,1,1) local gravity_x = 0 local gravity_y = -9.8 --very slow to be able to see tPhysic = box2d:new(gravity_x,gravity_y) tShapeQuad = shape:new('2dw',-100, 300) tShapeCircle = shape:new('2dw', 0, 200) tShapeTriangle = shape:new('2dw', 50, 100) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeQuad) --heavy tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) tPhysic:setEnable(tShapeCircle,false) .. figure:: _static/box_2d_setEnable.gif :align: center :figclass: align-center Enable/disable box2d body Internally it will change all fixture mask bits as is showing bellow: .. code-block:: c++ 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(); } .. data:: 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,'** :param renderizable: **body** (optional). :param b2Filter: **filter** box2d. The filter shall have this members (default values): .. code-block:: lua 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:* .. code-block:: lua require "box2d" mbm.setColor(1,1,1) local gravity_x = 0 local gravity_y = -9.8 --very slow to be able to see tPhysic = box2d:new(gravity_x,gravity_y) tFilterA = { categoryBits = 1, -- I am A (0000-0001) maskBits = 132, -- Collide with C,D (1000-0100) groupIndex = 0} -- Override collision tFilterB = { categoryBits = 2, -- I am B (0000-0010) maskBits = 128, -- Collide with D (1000-0000) groupIndex = 0} -- Override collision tFilterC = { categoryBits = 4, -- I am C (0000-0100) maskBits = 129, -- Collide with A,D (1000-0001) groupIndex = 0} -- Override collision tFilterD = { categoryBits = 128, -- I am D (1000-0000) maskBits = 255, -- Collide with all (1111-1111) groupIndex = 0} -- Override collision tShapeQuad = shape:new('2dw', -20, 300) tShapeCircle = shape:new('2dw', 0, 200) tShapeTriangle = shape:new('2dw', 50, 100) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) tPhysic:setFilter(tShapeQuad, tFilterA) tPhysic:setFilter(tShapeCircle, tFilterB) tPhysic:setFilter(tShapeTriangle, tFilterC) tPhysic:setFilter(tShapeGround, tFilterD) .. figure:: _static/box_2d_setFilter.gif :align: center :figclass: align-center box2d setFilter Force options body ^^^^^^^^^^^^^^^^^^ .. data:: applyForce(tBody,number fx, number fy, number * wx, number *wy) :noindex: 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. :param renderizable: **body**. :param number: **fx** force world, usually in Newtons (N). :param number: **fy** force world, usually in Newtons (N). :param number: **wx** point the world position of the point of application. :param number: **wy** point the world position of the point of application. *Example:* .. code-block:: lua :emphasize-lines: 21,25 require "box2d" tPhysic = box2d:new() tPhysic:setScale(10) tShapeQuad = shape:new('2dw',-310, 50) tShapeCircle = shape:new('2dw', 0, 300) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',40,40) tShapeCircle:create('circle',40,40) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addStaticBody(tShapeGround) function onKeyDown(key) local force = 20000 local wx,wy = tPhysic:getWorldCenter(tShapeQuad) --same effect as applyForceToCenter if mbm.getKeyCode('up') == key then -- in this example we keep pressing to up tPhysic:applyForce(tShapeQuad,0 ,force, wx, wy) elseif mbm.getKeyCode('left') == key then tPhysic:applyForce(tShapeQuad,-force,0, wx, wy) elseif mbm.getKeyCode('right') == key then -- and in the air right tPhysic:applyForce(tShapeQuad,force,0, wx, wy) end end .. figure:: _static/box_2d_example_applyForce.gif :align: center :figclass: align-center box2d applying force .. data:: applyForceToCenter(tBody,number fx, number fy) Apply a force at a world point at the center of mass, :param renderizable: **body**. :param number: **fx** force world, usually in Newtons (N). :param number: **fy** force world, usually in Newtons (N). *Example:* .. code-block:: lua :emphasize-lines: 24 require "box2d" tPhysic = box2d:new() tPhysic:setScale(10) tShapeQuad = shape:new('2dw',-310, 50) tShapeCircle = shape:new('2dw', 0, 300) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',40,40) tShapeCircle:create('circle',40,40) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addStaticBody(tShapeGround) function onKeyDown(key) local force = 20000 if mbm.getKeyCode('up') == key then tPhysic:applyForceToCenter(tShapeQuad,0 ,force) elseif mbm.getKeyCode('left') == key then tPhysic:applyForceToCenter(tShapeQuad,-force,0) elseif mbm.getKeyCode('right') == key then tPhysic:applyForceToCenter(tShapeQuad,force,0) -- in this example we keep pressing to right end end .. figure:: _static/box_2d_example_applyForceToCenter.gif :align: center :figclass: align-center box2d applying force to center .. data:: applyLinearImpulse(tBody,number fx, number fy, number * wx, number *wy) :noindex: 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. :param renderizable: **body**. :param number: **fx** force world, usually in Newtons (N). :param number: **fy** force world, usually in Newtons (N). :param number: **wx** point the world position of the point of application. :param number: **wy** point the world position of the point of application. *Example:* .. code-block:: lua :emphasize-lines: 25 require "box2d" tPhysic = box2d:new() tPhysic:setScale(10) tShapeQuad = shape:new('2dw',-310, 50) tShapeCircle = shape:new('2dw', 0, 300) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',40,40) tShapeCircle:create('circle',40,40) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addStaticBody(tShapeGround) function onKeyDown(key) local force = 2000 local wx,wy = tPhysic:getWorldCenter(tShapeQuad) if mbm.getKeyCode('up') == key then tPhysic:applyLinearImpulse(tShapeQuad,0 ,force, wx, wy) elseif mbm.getKeyCode('left') == key then tPhysic:applyLinearImpulse(tShapeQuad,-force,0, wx, wy) elseif mbm.getKeyCode('right') == key then -- in this example we pressed once to right tPhysic:applyLinearImpulse(tShapeQuad,force,0, wx, wy) end end .. figure:: _static/box_2d_example_applyLinearImpulse.gif :align: center :figclass: align-center box2d applying linear impulse .. data:: applyLinearImpulseToCenter(tBody,number fx, number fy) Apply an impulse to the center of mass. This immediately modifies the velocity. :param renderizable: **body**. :param number: **fx** force world, usually in Newtons (N). :param number: **fy** force world, usually in Newtons (N). *Example:* .. code-block:: lua :emphasize-lines: 20 require "box2d" tPhysic = box2d:new() tPhysic:setScale(10) tShapeQuad = shape:new('2dw',-310, 50) tShapeCircle = shape:new('2dw', 0, 300) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',40,40) tShapeCircle:create('circle',40,40) tShapeGround:create('rectangle',1000,20) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addStaticBody(tShapeGround) function onKeyDown(key) local force = 2000 if mbm.getKeyCode('up') == key then tPhysic:applyLinearImpulseToCenter(tShapeQuad,0 ,force) -- in this example we pressed once to up elseif mbm.getKeyCode('left') == key then tPhysic:applyLinearImpulseToCenter(tShapeQuad,-force,0) elseif mbm.getKeyCode('right') == key then tPhysic:applyLinearImpulseToCenter(tShapeQuad,force,0) end end .. figure:: _static/box_2d_example_applyLinearImpulseToCenter.gif :align: center :figclass: align-center box2d applying linear impulse to center .. data:: applyAngularImpulse(tBody, number angular_impulse, boolean * wake) Apply an angular impulse. :param renderizable: **body**. :param number: **angular impulse** in units of kg*m*m/s. :param boolean: **wake** up the body (default is ``true``). *Example:* .. code-block:: lua tPhysic:applyAngularImpulse(tBody,50,true) Friction options body ^^^^^^^^^^^^^^^^^^^^^ .. data:: setFriction(tBody,number friction, boolean update_contact_list) Set the coefficient of friction. By default the engine also set the friction on contact list. :param renderizable: **body**. :param number: **friction** coefficient. :param boolean: **update contact list** flag (default is ``true``). *Example:* .. code-block:: lua tPhysic:setFriction(tBody,5,true) Gravity options body ^^^^^^^^^^^^^^^^^^^^ .. data:: getGravityScale(tBody) :noindex: Get the gravity scale of the body. :param renderizable: **body**. :return: ``number`` - *gravity scale* *Example:* .. code-block:: lua local gravity_scale = tPhysic:getGravityScale(tBody) .. data:: setGravityScale(tBody, number gravity_scale) :noindex: Set the gravity scale of the body. :param renderizable: **body**. :param number: **gravity scale**. *Example:* .. code-block:: lua tPhysic:setGravity(tBody,2.0) Inertia options body ^^^^^^^^^^^^^^^^^^^^ .. data:: getInertia(tBody) Get the rotational inertia of the body about the local origin. :param renderizable: **body**. :return: ``number`` - The rotational inertia, usually in kg-m^2. *Example:* .. code-block:: lua local inertia = tPhysic:getInertia(tBody) Mass options body ^^^^^^^^^^^^^^^^^ .. data:: getMass(tBody) Get the total mass of the body. :param renderizable: **body**. :return: ``number`` - the mass, usually in kilograms (kg). *Example:* .. code-block:: lua local mass = tPhysic:getMass(tBody) .. data:: setMass(tBody) The mass of the shape, usually in kilograms. :param renderizable: **body**. :param number: **mass**. *Example:* .. code-block:: lua tPhysic:setMass(tBody,10) 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. .. data:: addKinematicBody(renderizable mesh, number * density, number * friction, number * restitution, number * reduceX, number * reduceY, boolean * isSensor) Create a new instance of a ``kinematic`` :ref:`body `. :param renderizable: any type of :ref:`mesh ` previouslly loaded according. :param number: **density** default is ``1.0``. :param number: **friction** default is ``10.0``. :param number: **restitution** default is ``0.1``. :param number: **scale** of reduction on ``x`` axis. default is ``1.0`` (real size). :param number: **scale** of reduction on ``y`` axis. default is ``1.0`` (real size). :param boolean: **sensor** flag (``true`` or ``false``) default is ``false``. :return: :ref:`body ` *table*. *For this example let's create a kinematic body as a square:* .. code-block:: lua :emphasize-lines: 24 require "box2d" mbm.setColor(1,1,1) --set background color to white local gravity_x = 0 local gravity_y = -9.8 --very slow to be able to see tPhysic = box2d:new(gravity_x,gravity_y) tShapeQuad = shape:new('2dw',-310, 50) tShapeCircle = shape:new('2dw', 0, 500) tShapeTriangle = shape:new('2dw', 50, 300) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) local density, friction, restitution = 1, 10, 0.8 -- restitution 0.1 -> 0.8 (super) tPhysic:addDynamicBody(tShapeCircle,density, friction, restitution) tPhysic:addKinematicBody(tShapeQuad) tPhysic:setLinearVelocity(tShapeQuad,2,0) -- move right 2 unit per second tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) .. figure:: _static/box_2d_example_creating_kinematic_body.gif :align: center :figclass: align-center Creating kinematic body .. _get_position_box2d: Position options body ^^^^^^^^^^^^^^^^^^^^^ .. data:: getPosition(tBody) Get the body position **NOT** considering the :ref:`box2d scale ` . :param renderizable: **body**. :return: ``number`` *x* - ``number`` - *y* . *Example:* .. code-block:: lua 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 Restitution options body ^^^^^^^^^^^^^^^^^^^^^^^^ .. data:: setRestitution(tBody,number restitution, boolean update_contact_list) Set the coefficient of restitution. By default the engine also set the restitution on contact list. :param renderizable: **body**. :param number: **restitution** coefficient. :param boolean: **update contact list** flag (default is ``true``). *Example:* .. code-block:: lua tPhysic:setRestitution(tBody,10,true) Rotation options body ^^^^^^^^^^^^^^^^^^^^^ .. data:: setFixedRotation(tBody, boolean value) Set this body to have fixed rotation. This causes the mass to be reset. :param renderizable: **body**. :param boolean: **value**. *Example:* .. code-block:: lua tPhysic:setFixedRotation(tBody,true) Sleep options body ^^^^^^^^^^^^^^^^^^ .. data:: setSleepingAllowed(tBody, boolean value) Disable sleeping on body. If you disable sleeping, the body will be woken. :param renderizable: **body**. :param boolean: **value**. *Example:* .. code-block:: lua tPhysic:setSleepingAllowed(tBody,false) State options body ^^^^^^^^^^^^^^^^^^ .. data:: isActive(tBody) Get the active state of the body. :param renderizable: **body**. :return: ``boolean`` - *is active* *Example:* .. code-block:: lua local is_active = tPhysic:isActive(tBody) print('Body is active?:', tostring(is_active)) .. data:: isAwake(tBody) Get the sleeping state of this body. :param renderizable: **body**. :return: ``boolean`` - *is awake* *Example:* .. code-block:: lua local is_awake = tPhysic:isActive(tBody) print('Body is awake?:', tostring(is_awake)) .. data:: 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. :param renderizable: **body**. :param boolean: **value**. *Example:* .. code-block:: lua tPhysic:setActive(tBody,true) .. data:: setAwake(tBody,boolean value) Set the sleep state of the body. A sleeping body has very low CPU cost. :param renderizable: **body**. :param boolean: **value**. *Example:* .. code-block:: lua tPhysic:setAwake(tBody,false) 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. .. data:: addStaticBody(renderizable mesh, number * density, number * friction, number * reduceX, number * reduceY, boolean * isSensor) Create a new instance of a ``static`` :ref:`body `. :param renderizable: any type of :ref:`mesh ` previouslly loaded according. :param number: **density** default is ``0.0``. :param number: **friction** default is ``0.3``. :param number: **scale** of reduction on ``x`` axis. default is ``1.0`` (real size). :param number: **scale** of reduction on ``y`` axis. default is ``1.0`` (real size). :param boolean: **sensor** flag (``true`` or ``false``) default is ``false``. :return: :ref:`body ` *table*. *For this example let's create a ground which represent the static body:* .. code-block:: lua :emphasize-lines: 24 require "box2d" mbm.setColor(1,1,1) local gravity_x = 0 local gravity_y = -9.8 --very slow to be able to see tPhysic = box2d:new(gravity_x,gravity_y) tShapeQuad = shape:new('2dw',-20, 720) tShapeCircle = shape:new('2dw',100, 500) tShapeTriangle = shape:new('2dw',50 , 300) tShapeGround = shape:new('2dw',0,-50) tShapeQuad:create('rectangle',100,100) tShapeCircle:create('circle',100,100) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',500,20) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) .. figure:: _static/box_2d_example_creating_static_body.gif :align: center :figclass: align-center Creating a static body named tShapeGround Test point on body ^^^^^^^^^^^^^^^^^^ .. data:: testPoint(tBody,number x, number y) Test a point for containment in all fixture from a body. It considers :ref:`box2d ` :ref:`scale `. :param renderizable: **body**. :param number: **x** in world coordinates. :param number: **y** in world coordinates. :return: ``boolean`` - *hit* any fixture *Example:* .. code-block:: lua :emphasize-lines: 13 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tPhysic:setScale(15) tShapeQuad = shape:new('2dw', -20, -20) tShapeQuad:create('rectangle', 100,200) tPhysic:addStaticBody(tShapeQuad) function onTouchMove(key,x,y) x,y = mbm.to2dw(x,y) if tPhysic:testPoint(tShapeQuad,x,y) then tShapeQuad:setColor(0.8,0,0) else tShapeQuad:setColor(0.8,0,0.8) end end .. figure:: _static/box_2d_testPoint.gif :align: center :figclass: align-center testPoint box2d Torque options body ^^^^^^^^^^^^^^^^^^^ .. data:: applyTorque(tBody,number torque, boolean * wake) Apply a torque. This affects the angular velocity without affecting the linear velocity of the center of mass. :param renderizable: **body**. :param number: **torque** about the z-axis (out of the screen), usually in N-m. :param boolean: **wake** up the body (default is ``true``). *Example:* .. code-block:: lua tPhysic:applyTorque(tBody,50,true) Transform options body ^^^^^^^^^^^^^^^^^^^^^^ .. Important:: You should consider the :ref:`box2d scale ` to everything related to any transform method to real world and vice versa. .. data:: 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. :param number: **x** position of body. :param number: **y** position of body. :param number: **angle** ``z`` of body. *Example:* .. code-block:: lua :emphasize-lines: 13,14 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: .. code-block:: c++ const float scalePercentage = 1.0f / box2d->scale; const b2Vec2 position(newPosition->x * scalePercentage,newPosition->y * scalePercentage); body->SetTransform(position,newAngleDegree); .. data:: getWorldCenter(tBody) Get the world position of the center of mass. :param renderizable: **body**. :return: ``number`` *x* - ``number`` - *y* . *Example:* .. code-block:: lua :emphasize-lines: 9 require "box2d" tPhysic = box2d:new() tPhysic:setScale(1) tShapeQuad = shape:new('2dw',45,38) --put some place different from origin tShapeQuad:create('rectangle',100,100) tPhysic:addStaticBody(tShapeQuad) local px, py = tPhysic:getWorldCenter(tShapeQuad) tShapePoint = shape:new('2dw') tShapePoint:create('circle',10,10) tShapePoint:setPos(px,py) tShapePoint:setColor(0,0,1) -- our blue point print('px:',px,'py:',py) .. figure:: _static/box_2d_getWorldCenter.png :align: center :figclass: align-center box2d getWorldCenter method .. _getWorldPoint_box2d: .. data:: getWorldPoint(tBody,number x,number y) The function getWorldPoint is used to convert a location relative to the body (body coordinates) into world coordinates. :param renderizable: **body**. :param number: **x** point on the body measured relative the the body's origin. :param number: **y** point on the body measured relative the the body's origin. :return: ``number`` *x* - ``number`` - *y* . *Example:* .. code-block:: lua :emphasize-lines: 11 require "box2d" tPhysic = box2d:new() tPhysic:setScale(1) tShapeQuad = shape:new('2dw',66,99) --put some place different from origin tShapeQuad:create('rectangle',100,100) tShapeQuad.az = math.rad(10) -- tilt 10 degree tPhysic:addStaticBody(tShapeQuad) local x, y = 50,50 -- we know the size local px, py = tPhysic:getWorldPoint(tShapeQuad,x,y) tShapePoint = shape:new('2dw') tShapePoint:create('circle',10,10) tShapePoint:setPos(px,py) tShapePoint:setColor(0,0,1) -- our blue point print('px:',px,'py:',py) .. figure:: _static/box_2d_getWorldPoint.png :align: center :figclass: align-center box2d getWorldPoint method .. _getWorldVector_box2d: .. data:: getWorldVector(tBody,number x,number y) Get the world coordinates of a vector given the local coordinates. :param renderizable: **body**. :param number: **x** local fixed in the body. :param number: **y** local fixed in the body. :return: ``number`` *x* - ``number`` - *y* . *Example:* .. code-block:: lua :emphasize-lines: 11 require "box2d" tPhysic = box2d:new() tPhysic:setScale(1) tShapeQuad = shape:new('2dw',50,50) tShapeQuad:create('rectangle',100,100) tShapeQuad.az = math.rad(180) -- tilt 180 degree tPhysic:addStaticBody(tShapeQuad) local x, y = 100,100 local px, py = tPhysic:getWorldVector(tShapeQuad,x,y) tShapePoint = shape:new('2dw') tShapePoint:create('circle',10,10) tShapePoint:setPos(px,py) tShapePoint:setColor(0,0,1) -- our blue point print('px:',px,'py:',py) .. figure:: _static/box_2d_getWorldVector.png :align: center :figclass: align-center box2d getWorldVector method .. data:: getLocalPoint(tBody) Gets a local point relative to the body's origin given a world point. :param renderizable: **body**. :param number: **x** world coordinates. :param number: **y** world coordinates. :return: ``number`` *x* - ``number`` - *y* corresponding local point relative to the body's origin. *Example:* .. code-block:: lua local x,y = tPhysic:getLocalPoint(tBody,10,5) .. data:: getLocalCenter(tBody) Get the local position of the center of mass. :param renderizable: **body**. :return: ``number`` *x* - ``number`` - *y* local center. *Example:* .. code-block:: lua local x,y = tPhysic:getLocalCenter(tBody) Type options body ^^^^^^^^^^^^^^^^^ .. data:: setType(tBody,string type) Set the type of body. This may alter the mass and velocity. Acceptable types are:``static``, ``kinematic`` or ``dynamic``. :param renderizable: **body**. :param string: **type** of body. *Example:* .. code-block:: lua tPhysic:setType(tBody,'static') .. data:: getType(tBody) Retrieve the body type. The possible types are:``static``, ``kinematic`` or ``dynamic``. :param renderizable: **body**. :return: ``string`` - *type* *Example:* .. code-block:: lua local type_body = tPhysic:getType(tBody) Velocity options body ^^^^^^^^^^^^^^^^^^^^^ .. data:: getLinearVelocity(tBody) Get the linear velocity of the center of mass. :param renderizable: **body**. :return: ``number`` *x* - ``number`` - *y* the linear velocity of the center of mass. *Example:* .. code-block:: lua local lx,ly = tPhysic:getLinearVelocity(tBody) .. data:: getAngularVelocity(tBody) Get the angular velocity. :param renderizable: **body**. :return: ``number`` - *angular velocity* in radians/second. *Example:* .. code-block:: lua local angular_velocity = tPhysic:getAngularVelocity(tBody) .. data:: setAngularVelocity(tBody, number omega) Set the angular velocity. :param renderizable: **body**. :param number: **omega**. the new angular velocity in radians/second. *Example:* .. code-block:: lua local omega = math.rad(15) tPhysic:setAngularVelocity(tBody,omega) .. data:: setLinearVelocity(tBody, number x, number y) Set the linear velocity of the center of mass. :param renderizable: **body**. :param number: **x**. the new linear velocity of the center of mass. :param number: **y**. the new linear velocity of the center of mass. *Example:* .. code-block:: lua tPhysic:setLinearVelocity(tBody,50,2) .. _box2d_joint: box2d Joint ----------- Box2D has a lot of :ref:`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 :ref:`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: .. code-block:: lua 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. Joints definition ^^^^^^^^^^^^^^^^^ Let's see the :ref:`joints ` available for :ref:`box2d ` and its characteristics: Distance joint """""""""""""" .. _Distance_joint_box2d: :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: .. code-block:: lua 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 :guilabel:`b2DistanceJointDef::Initialize`) | These parameters Initialize ``localAnchorA``, ``localAnchorB`` and ``length``. | You should consider the :ref:`box2d scale ` for ``localAnchorA``, ``localAnchorB``, ``length``, ``anchor1`` and ``anchor2``. | | The extra parameters for this joint table are: .. code-block:: lua 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. Friction joint """""""""""""" .. _Friction_joint_box2d: :Friction: - Reduces the relative motion between the two bodies. Here the table definition: .. code-block:: lua 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 :guilabel:`b2FrictionJointDef::Initialize`) | This parameter Initialize ``localAnchorA`` and ``localAnchorB``. | You should consider the :ref:`box2d scale ` for ``localAnchorA``, ``localAnchorB``, and ``anchor``. | | The extra parameter for this joint is described bellow: .. code-block:: lua 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. Gear joint """""""""" .. _Gear_joint_box2d: :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: .. code-block:: lua 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. Motor joint """"""""""" .. _Motor_joint_box2d: :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: .. code-block:: lua tJoint = { name = 'motor', linearOffset = { x = 0, y = 0}, angularOffset = 0.0, maxForce = 1.0, maxTorque = 1.0, correctionFactor = 0.3, collideConnected = false, } Mouse joint """"""""""" .. _Mouse_joint_box2d: :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: .. code-block:: lua tJoint = { name = 'mouse', target = {x = 0, y = 0}, maxForce = 0.0, frequencyHz = 5.0, dampingRatio = 0.7, collideConnected = false, } .. Note:: :ref:`Mouse joint ` does **not** need a second body however to keep the signature, we pass it twice on :ref:`create joint method `. Prismatic joint """"""""""""""" .. _Prismatic_joint_box2d: :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: .. code-block:: lua 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 :guilabel:`b2PrismaticJointDef::Initialize`) | These parameters Initialize ``localAnchorA``, ``localAnchorB`` and ``localAxisA``. | You should consider the :ref:`box2d scale ` for ``localAnchorA``, ``localAnchorB``, and ``anchor``. | | The extra parameters for this joint table are: .. code-block:: lua 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. Pulley joint """""""""""" .. _Pulley_joint_box2d: :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: .. code-block:: lua 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 :guilabel:`b2PulleyJointDef::Initialize`) | These parameters Initialize ``localAnchorA``, ``localAnchorB``, ``groundAnchorA``, ``groundAnchorB``, ``lengthA`` and ``lengthB``. | You should consider the :ref:`box2d scale ` for ``localAnchorA``, ``localAnchorB``, ``groundAnchorA``, ``groundAnchorB``, ``lengthA`` and ``lengthB``. | | The extra parameters for this joint table are: .. code-block:: lua 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`` Revolute joint """""""""""""" .. _Revolute_joint_box2d: :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: .. code-block:: lua 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 :guilabel:`b2RevoluteJointDef::Initialize`) | This parameter Initialize ``localAnchorA``, ``localAnchorB`` and ``referenceAngle``. | You should consider the :ref:`box2d scale ` for ``localAnchorA``, ``localAnchorB`` and ``anchor``. | | The extra parameter for this joint is described bellow: .. code-block:: lua 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. Rope joint """""""""" .. _Rope_joint_box2d: :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: .. code-block:: lua 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 :guilabel:`b2_linearSlop` (*0.005*) or the joint will have no effect. Weld joint """""""""" .. _Weld_joint_box2d: :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: .. code-block:: lua 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 :guilabel:`b2WeldJointDef::Initialize`) | This parameter Initialize ``localAnchorA``, ``localAnchorB`` and ``referenceAngle``. | You should consider the :ref:`box2d scale ` for ``localAnchorA``, ``localAnchorB``, and ``anchor``. | | The extra parameter for this joint is described bellow: .. code-block:: lua 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. Wheel joint """"""""""" .. _Wheel_joint_box2d: :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: .. code-block:: lua 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 :guilabel:`b2WheelJointDef::Initialize`) | These parameters Initialize ``localAnchorA``, ``localAnchorB`` and ``localAxisA``. | You should consider the :ref:`box2d scale ` for ``localAnchorA``, ``localAnchorB``, and ``anchor``. | | The extra parameters for this joint table are: .. code-block:: lua 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. .. _create_joint_box2d: Creating joint ^^^^^^^^^^^^^^ .. data:: joint(tBody_A,tBody_B,tJoint) The signature is always like this. The first body then the second and the joint table definition. :param renderizable: **first body**. :param renderizable: **second body**. :param table: **joint definition**. see :ref:`box2d joint ` :return: ``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 :guilabel:`joint` use :ref:`getJoint ` method and prefer to pass the absolute index. Distance joint """""""""""""" Next, an example of :ref:`joint ` using :ref:`distance joint ` table. .. code-block:: lua :emphasize-lines: 43 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tShapeQuad = shape:new('2dw',-200, 720) tShapeCircle1 = shape:new('2dw',-100, 400) tShapeCircle2 = shape:new('2dw', 100, 400) tShapeTriangle = shape:new('2dw', 50, 300) tShapeGround = shape:new('2dw',0,-50) tShapeWall = shape:new('2dw',300,100) tShapeQuad:create('rectangle',100,100) tShapeCircle1:create('circle',100,100) tShapeCircle2:create('circle',80,80) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) tShapeWall:create('rectangle',20,200) local density, friction, restitution = 0.5, 10, 1.0 tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution) tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeWall) tJoint = { name = 'distance', localAnchorA = {x = 0.0, y = 0.0}, localAnchorB = {x = 0.0, y = 0.0}, --length: we are omitting the distance let the engine calculate it frequencyHz = 0.0, dampingRatio = 0.0, collideConnected = false } local indexJoint = tPhysic:joint(tShapeCircle1,tShapeCircle2,tJoint) .. figure:: _static/box_2d_joint_distance.gif :align: center :figclass: align-center Distance joint Friction joint """""""""""""" Next, an example of :ref:`joint ` using :ref:`friction joint ` table. .. code-block:: lua :emphasize-lines: 42 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tShapeQuad = shape:new('2dw',-200, 720) tShapeCircle1 = shape:new('2dw',-100, 400) tShapeCircle2 = shape:new('2dw', 100, 400) tShapeTriangle = shape:new('2dw', 50, 300) tShapeGround = shape:new('2dw',0,-50) tShapeWall = shape:new('2dw',300,100) tShapeQuad:create('rectangle',100,100) tShapeCircle1:create('circle',100,100) tShapeCircle2:create('circle',80,80) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) tShapeWall:create('rectangle',20,200) local density, friction, restitution = 0.5, 10, 1.0 tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution) tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeWall) tJoint = { name = 'friction', localAnchorA = {x = 0, y = 0}, localAnchorB = {x = 0, y = 0}, maxForce = 5000.0, maxTorque = 5000.0, collideConnected = true } local indexJoint = tPhysic:joint(tShapeQuad,tShapeGround,tJoint) .. figure:: _static/box_2d_joint_friction.gif :align: center :figclass: align-center Friction joint Gear joint """""""""" Next, an example of :ref:`joint ` using :ref:`gear joint ` table. .. code-block:: lua :emphasize-lines: 93 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tShapeBoxMain = shape:new('2dw',0, 100) tShapeBoxLeft = shape:new('2dw',-50, 150) tShapeBoxRight = shape:new('2dw',50, 150) tShapeCircle = shape:new('2dw',400, 500) tShapeGround = shape:new('2dw',0,40) tShapeRightWall = shape:new('2dw',450,0) tShapeBoxMain:create('rectangle',100,100) tShapeBoxLeft:create('rectangle',50,50) tShapeBoxRight:create('rectangle',50,50) tShapeCircle:create('circle',100,100) tShapeGround:create('rectangle',1000,20) tShapeRightWall:create('rectangle',20,400) tShapeGround.az = math.rad(2) --tilt a litle bit tPhysic:addDynamicBody(tShapeBoxMain) tPhysic:addDynamicBody(tShapeBoxLeft) tPhysic:addDynamicBody(tShapeBoxRight) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeRightWall) local size_box = {x = 0, y = 0} size_box.x, size_box.y = tShapeBoxMain:getSize() size_box.x = size_box.x / tPhysic:getScale() --consider the box2d scale size_box.y = size_box.y / tPhysic:getScale() --consider the box2d scale local corner_box_left = {x = size_box.x / 2,y = size_box.y / 2} -- corner of the box (top,left) local corner_box_right = {x = -size_box.x / 2,y = size_box.y / 2} -- corner of the box (top,right) --[[ corner box top left -> *-------* <- corner_box top,right | main | | box | |-------| ]] tJointLeft = { name = 'revolute', localAnchorA = corner_box_left, --in the corner of the box A (top,left) localAnchorB = {x = 0, y =0}, --in the center of the left box referenceAngle = tShapeBoxLeft.az - tShapeBoxMain.az, lowerAngle = math.rad(-90), -- no effect since enableLimit is false upperAngle = math.rad(45), -- no effect since enableLimit is false maxMotorTorque = 10000.0, motorSpeed = 10.0, enableLimit = false, enableMotor = false, collideConnected = false, } tJointRight = { name = 'revolute', localAnchorA = corner_box_right, --in the corner of the box A (top,right) localAnchorB = {x = 0, y =0}, --in the center of the rigth box referenceAngle = tShapeBoxLeft.az - tShapeBoxMain.az, lowerAngle = math.rad(-90), -- no effect since enableLimit is false upperAngle = math.rad(45), -- no effect since enableLimit is false maxMotorTorque = 10000.0, motorSpeed = 10.0, enableLimit = false, enableMotor = false, collideConnected = false, } local indexA = tPhysic:joint(tShapeBoxMain,tShapeBoxLeft,tJointLeft) local indexB = tPhysic:joint(tShapeBoxMain,tShapeBoxRight,tJointRight) tJLeft = tPhysic:getJoint(tShapeBoxLeft) tJRight = tPhysic:getJoint(tShapeBoxRight) tJoint = { name = 'gear', ratio = 1.0, indexA = indexA, indexB = indexB, collideConnected = false } local indexJointGear = tPhysic:joint(tShapeBoxLeft,tShapeBoxRight,tJoint) .. figure:: _static/box_2d_joint_gear.gif :align: center :figclass: align-center Gear joint Motor joint """"""""""" Next, an example of :ref:`joint ` using :ref:`motor joint ` table. .. code-block:: lua :emphasize-lines: 46 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tShapeQuad = shape:new('2dw',-200, 520) tShapeCircle1 = shape:new('2dw',-80, 400) tShapeCircle2 = shape:new('2dw', 100, 400) tShapeTriangle = shape:new('2dw', 50, 300) tShapeGround = shape:new('2dw',0,-300) tShapeRightWall = shape:new('2dw',450,0) tShapeLeftWall = shape:new('2dw',-450,0) tShapeQuad:create('rectangle',100,100) tShapeCircle1:create('circle',200,200,10) --low resolution of the circle tShapeCircle2:create('circle',80,80) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) tShapeRightWall:create('rectangle',20,400) tShapeLeftWall:create('rectangle',20,400) local density, friction, restitution = 0.5, 10, 1.0 tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution) tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeLeftWall) tPhysic:addStaticBody(tShapeRightWall) tJoint = { name = 'motor', linearOffset = { x = 15, y = 0}, --relative distance between body 2 and body 1 angularOffset = math.rad(180.0), --relative angle between body 2 and body 1 maxForce = 100000.0, maxTorque = 10000.0, correctionFactor = 1.3, collideConnected = false, } local indexJoint = tPhysic:joint(tShapeQuad,tShapeCircle1,tJoint) .. figure:: _static/box_2d_joint_motor.gif :align: center :figclass: align-center Motor joint Mouse joint """"""""""" Next, an example of :ref:`joint ` using :ref:`mouse joint ` table. .. code-block:: lua :emphasize-lines: 75 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tPhysic:setScale(10) --set our desired scale tShapeQuad = shape:new('2dw',-200, 300) tShapeCircle1 = shape:new('2dw',-100, 300) tShapeCircle2 = shape:new('2dw', 100, 300) tShapeTriangle = shape:new('2dw', 50, 300) tShapeGround = shape:new('2dw',0,-350) tShapeLeftWall = shape:new('2dw',-400,0) tShapeRightWall = shape:new('2dw',400,0) tShapeUpWall = shape:new('2dw',0,350) tShapeQuad:create('rectangle',100,100) tShapeCircle1:create('circle',100,100) tShapeCircle2:create('circle',80,80) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) tShapeRightWall:create('rectangle',20,700) tShapeLeftWall:create('rectangle',20,700) tShapeUpWall:create('rectangle',1000,20) local density, friction, restitution = 0.5, 10, 1.0 tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution) tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeRightWall) tPhysic:addStaticBody(tShapeLeftWall) tPhysic:addStaticBody(tShapeUpWall) tAllDynamicObject = {} --store all dynamic objects that we want to apply mouse joint table.insert(tAllDynamicObject,tShapeQuad) table.insert(tAllDynamicObject,tShapeCircle1) table.insert(tAllDynamicObject,tShapeCircle2) table.insert(tAllDynamicObject,tShapeTriangle) --our mouse joint table tJoint = { name = 'mouse', target = {x=0,y=0}, -- updated in the moment that we click on object and keep clicked maxForce = 0, -- updated according to mass frequencyHz = 30.0, dampingRatio = 0.7, collideConnected = false, } tMouseJoint = nil --point to mouse joint when created tMeshJoint = nil --point to mesh that we have selected (clicked) --called onTouchDown and onTouchMove function setTarget(x,y) x , y = x / tPhysic:getScale(),y / tPhysic:getScale() -- we have to consider the scale if tMouseJoint then tMouseJoint:setTarget(x,y) end tJoint.target.x,tJoint.target.y = x,y end function onTouchDown(key,x,y) x,y = mbm.to2dw(x,y) for i = 1, #tAllDynamicObject do local tMesh = tAllDynamicObject[i] if tPhysic:testPoint(tMesh,x,y) and tMouseJoint == nil then tJoint.maxForce = 1000 * tPhysic:getMass(tMesh) setTarget(x,y) -- update the target if tPhysic:joint(tMesh,tMesh,tJoint) > 0 then tMouseJoint = tPhysic:getJoint(tMesh) tMeshJoint = tAllDynamicObject[i] break end end end end function onTouchMove(key,x,y) if tMouseJoint then x , y = mbm.to2dw(x,y) setTarget(x,y)-- update the target end end function onTouchUp(key,x,y) if tMouseJoint then tPhysic:destroyJoint(tMeshJoint) --no long are holding the object, destroy it tMouseJoint = nil --mark as nil end end .. figure:: _static/box_2d_joint_mouse.gif :align: center :figclass: align-center Mouse joint .. Note:: | Note that we are considering the :ref:`box2d scale ` when we set the target through the method setTarget. | Also note that :ref:`mouse joint ` take the same body in the first and second argument. Prismatic joint """"""""""""""" Next, an example of :ref:`joint ` using :ref:`prismatic joint ` table. .. code-block:: lua :emphasize-lines: 67 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tShapeBoxA = shape:new('2dw',-300, 100) tShapeBoxB = shape:new('2dw',-350, 150) tShapeCircle = shape:new('2dw',400, 500) tShapeGround = shape:new('2dw',0,40) tShapeRightWall = shape:new('2dw',450,0) tShapeBoxA:create('rectangle',100,100) tShapeBoxB:create('rectangle',50,10) tShapeCircle:create('circle',100,100) tShapeGround:create('rectangle',1000,20) tShapeRightWall:create('rectangle',20,400) tShapeGround.az = math.rad(2) --tilt a litle bit tPhysic:addDynamicBody(tShapeBoxA) tPhysic:addDynamicBody(tShapeBoxB) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeRightWall) local size_box_a = {x = 0, y = 0} size_box_a.x, size_box_a.y = tShapeBoxA:getSize() size_box_a.x = size_box_a.x / tPhysic:getScale() --consider the box2d scale size_box_a.y = size_box_a.y / tPhysic:getScale() --consider the box2d scale local corner_box_a = {x = size_box_a.x / 2,y = -size_box_a.y / 2} -- corner of the box (bottom, right) local size_box_b = {x = 0, y = 0} size_box_b.x, size_box_b.y = tShapeBoxB:getSize() size_box_b.x = size_box_b.x / tPhysic:getScale() --consider the box2d scale size_box_b.y = size_box_b.y / tPhysic:getScale() --consider the box2d scale local corner_box_b = {x = -size_box_b.x / 2,y = -size_box_b.y / 2} -- corner of the box (bottom left) --[[ |-------| | | |-------| | box A | | | |-------* <- corner box a bottom,right | box B | corner box b bottom left -> *-------| ]] tJoint = { name = 'prismatic', localAnchorA = {x = corner_box_a.x, y = corner_box_a.y}, localAnchorB = {x = corner_box_b.x, y = corner_box_b.y}, localAxisA = {x = 0, y=1}, -- Direction of elevation (normalized) referenceAngle = 0.0, enableLimit = true, lowerTranslation = 0.0, upperTranslation = size_box_a.y, --How high? same as maximum of first box enableMotor = false, --enable on key up maxMotorForce = 50000.0, motorSpeed = 5.0, collideConnected = false, } local indexJoint = tPhysic:joint(tShapeBoxA,tShapeBoxB,tJoint) tJointPrismatic = tPhysic:getJoint(tShapeBoxA) function onKeyDown(key) if mbm.getKeyCode('up') == key then tJointPrismatic:enableMotor(true) end end function onKeyUp(key) if mbm.getKeyCode('up') == key then tJointPrismatic:enableMotor(false) end end .. figure:: _static/box_2d_joint_prismatic.gif :align: center :figclass: align-center Prismatic joint Pulley joint """""""""""" Next, an example of :ref:`joint ` using :ref:`pulley joint ` table. .. code-block:: lua :emphasize-lines: 43 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tPhysic:setScale(10) tShapeBox1 = shape:new('2dw',-200, -80) tShapeBox2 = shape:new('2dw', 200, -308) tShapeGround = shape:new('2dw',0,-350) tShapeGround:create('rectangle',1000,20) tShapeBox1:create('rectangle',100,100) tShapeBox2:create('rectangle',50,50) tPhysic:addDynamicBody(tShapeBox1) tPhysic:addDynamicBody(tShapeBox2) tPhysic:addStaticBody(tShapeGround) groundAnchorA = shape:new('2dw',-200,300) groundAnchorB = shape:new('2dw',200,300) groundAnchorA:create('circle',20,20) groundAnchorB:create('circle',20,20) size_box_2_y = select(2,tShapeBox2:getSize()) half_size_box_2_y = size_box_2_y / 2 box_2d_scale = tPhysic:getScale() tJoint = { name = 'pulley', groundAnchorA = {x = groundAnchorA.x / box_2d_scale , y = groundAnchorA.y / box_2d_scale}, groundAnchorB = {x = groundAnchorB.x / box_2d_scale , y = groundAnchorB.y / box_2d_scale}, localAnchorA = {x = 0.0 , y = 0.0}, localAnchorB = {x = 0.0 , y = half_size_box_2_y / box_2d_scale}, lengthA = 100.0 / box_2d_scale, lengthB = 400.0 / box_2d_scale, ratio = 1.0, collideConnected = true, } local indexJoint = tPhysic:joint(tShapeBox1,tShapeBox2,tJoint) .. figure:: _static/box_2d_joint_pulley.gif :align: center :figclass: align-center Pulley joint Revolute joint """""""""""""" Next, an example of :ref:`joint ` using :ref:`revolute joint ` table. .. code-block:: lua :emphasize-lines: 61 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tShapeBoxA = shape:new('2dw',0, 100) tShapeBoxB = shape:new('2dw',50, 150) tShapeCircle = shape:new('2dw',400, 500) tShapeGround = shape:new('2dw',0,40) tShapeRightWall = shape:new('2dw',450,0) tShapeBoxA:create('rectangle',100,100) tShapeBoxB:create('rectangle',50,50) tShapeCircle:create('circle',100,100) tShapeGround:create('rectangle',1000,20) tShapeRightWall:create('rectangle',20,400) tShapeGround.az = math.rad(2) --tilt a litle bit tPhysic:addDynamicBody(tShapeBoxA) tPhysic:addDynamicBody(tShapeBoxB) tPhysic:addDynamicBody(tShapeCircle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeRightWall) local size_box = {x = 0, y = 0} size_box.x, size_box.y = tShapeBoxA:getSize() size_box.x = size_box.x / tPhysic:getScale() --consider the box2d scale size_box.y = size_box.y / tPhysic:getScale() --consider the box2d scale local corner_box = {x = size_box.x / 2,y = size_box.y / 2} -- corner of the box (top,right) --[[ |-------* <- corner_box top,right | | | box A | |-------| ]] -- If we omit local anchors A and B, the engine will use the second body to calculate it. tJoint = { name = 'revolute', localAnchorA = corner_box, --in the corner of the box A (top,right) localAnchorB = {x = 0, y =0}, --in the center of the box B referenceAngle = tShapeBoxB.az - tShapeBoxA.az, lowerAngle = math.rad(-90), -- no effect since enableLimit is false upperAngle = math.rad(45), -- no effect since enableLimit is false maxMotorTorque = 10000.0, motorSpeed = 10.0, enableLimit = false, enableMotor = true, collideConnected = false, } local indexJoint = tPhysic:joint(tShapeBoxA,tShapeBoxB,tJoint) .. figure:: _static/box_2d_joint_revolute.gif :align: center :figclass: align-center Revolute joint Rope joint """""""""" Next, an example of :ref:`joint ` using :ref:`rope joint ` table. .. code-block:: lua :emphasize-lines: 41 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tShapeQuad = shape:new('2dw',-200, 720) tShapeCircle1 = shape:new('2dw',-100, 400) tShapeCircle2 = shape:new('2dw', 100, 400) tShapeTriangle = shape:new('2dw', 50, 300) tShapeGround = shape:new('2dw',0,-50) tShapeWall = shape:new('2dw',300,100) tShapeQuad:create('rectangle',100,100) tShapeCircle1:create('circle',100,100) tShapeCircle2:create('circle',80,80) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) tShapeWall:create('rectangle',20,200) local density, friction, restitution = 0.5, 10, 1.0 tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution) tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeWall) tJoint = { name = 'rope', localAnchorA = { x =-1.0, y = 0.0}, localAnchorB = { x = 1.0, y = 0.0}, --maxLength = 0.0, -- let the engine calculate the max length according to the current position of the bodies collideConnected = false, } local indexJoint = tPhysic:joint(tShapeCircle1,tShapeCircle2,tJoint) .. figure:: _static/box_2d_joint_rope.gif :align: center :figclass: align-center Rope joint Weld joint """""""""" Next, an example of :ref:`joint ` using :ref:`weld joint ` table. .. code-block:: lua :emphasize-lines: 51 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tShapeQuad = shape:new('2dw',-200, 520) tShapeCircle1 = shape:new('2dw',-80, 400) tShapeCircle2 = shape:new('2dw', 100, 400) tShapeTriangle = shape:new('2dw', 50, 300) tShapeGround = shape:new('2dw',0,-300) tShapeRightWall = shape:new('2dw',450,0) tShapeLeftWall = shape:new('2dw',-450,0) tShapeQuad:create('rectangle',100,100) tShapeCircle1:create('circle',200,200,10) --low resolution of the circle tShapeCircle2:create('circle',80,80) tShapeTriangle:create('triangle',100) tShapeGround:create('rectangle',1000,20) tShapeRightWall:create('rectangle',20,400) tShapeLeftWall:create('rectangle',20,400) local density, friction, restitution = 0.5, 10, 1.0 tPhysic:addDynamicBody(tShapeCircle1,density, friction, restitution) tPhysic:addDynamicBody(tShapeCircle2,density, friction, restitution) tPhysic:addDynamicBody(tShapeQuad) tPhysic:addDynamicBody(tShapeTriangle) tPhysic:addStaticBody(tShapeGround) tPhysic:addStaticBody(tShapeLeftWall) tPhysic:addStaticBody(tShapeRightWall) local world_point_a = { x = 0, y = 0 } local world_point_b = { x = 0, y = 0 } world_point_a.x, world_point_a.y = tPhysic:getLocalPoint(tShapeQuad,0,0) world_point_b.x, world_point_b.y = tPhysic:getLocalPoint(tShapeCircle1,0,0) tJoint = { name = 'weld', localAnchorA = world_point_a,-- If we omit local anchors A and B, the engine will use the second body to calculate it. localAnchorB = world_point_b,-- If we omit local anchors A and B, the engine will use the second body to calculate it. referenceAngle = tShapeQuad.az - tShapeCircle1.az, --if not supply, it will get the angle difference like this frequencyHz = 0.0, dampingRatio = 0.0, collideConnected = false, } local indexJoint = tPhysic:joint(tShapeQuad,tShapeCircle1,tJoint) .. figure:: _static/box_2d_joint_weld.gif :align: center :figclass: align-center Weld joint Wheel joint """"""""""" Next, an example of :ref:`joint ` using :ref:`wheel joint ` table. .. code-block:: lua :emphasize-lines: 59,69 require "box2d" mbm.setColor(1,1,1) tPhysic = box2d:new() tPhysic:setScale(10) tShapCar = shape:new('2dw', 0, 50) tShapeWheel1 = shape:new('2dw',-50, 25) tShapeWheel2 = shape:new('2dw', 50, 25) tShapeGround = shape:new('2dw',0,-25) tShapeGround:create('rectangle',1000,20) tShapCar:create('rectangle',100,50) tShapeWheel1:create('circle',50,50) tShapeWheel2:create('circle',50,50) tPhysic:addDynamicBody(tShapCar) tPhysic:addDynamicBody(tShapeWheel1) tPhysic:addDynamicBody(tShapeWheel2) tPhysic:addStaticBody(tShapeGround) -- Invert mass. See box2d tutorial the explanation local massCar = tPhysic:getMass(tShapCar) local massWheel = tPhysic:getMass(tShapeWheel1) tPhysic:setMass(tShapeWheel1,massCar * 0.5) tPhysic:setMass(tShapeWheel2,massCar * 0.5) tPhysic:setMass(tShapCar, massWheel * 2) tJoint = { name = 'wheel', localAnchorA = { x = 0, y = 0 }, localAnchorB = { x = 0, y = 0 }, localAxisA = { x = 0, y = 1 }, enableMotor = true, maxMotorTorque = 8000, motorSpeed = 0.0, frequencyHz = 3.0, dampingRatio = 0.9, collideConnected = false, } v1 = vec2:new() v2 = vec2:new() box_2d_scale = tPhysic:getScale() --find the relative local of back wheel v1:set(tShapCar.x,tShapCar.y) v2:set(tShapeWheel1.x,tShapeWheel1.y) v2:sub(v1) v2:div(box_2d_scale) tJoint.localAnchorA.x,tJoint.localAnchorA.y = v2.x,v2.y local indexJoint1 = tPhysic:joint(tShapCar,tShapeWheel1,tJoint) tShapCar.tJointWheel1 = tPhysic:getJoint(tShapeWheel1) --find the relative local of front wheel v1:set(tShapCar.x,tShapCar.y) v2:set(tShapeWheel2.x,tShapeWheel2.y) v2:sub(v1) v2:div(box_2d_scale) tJoint.localAnchorA.x, tJoint.localAnchorA.y = v2.x,v2.y local indexJoint2 = tPhysic:joint(tShapCar,tShapeWheel2,tJoint) tShapCar.tJointWheel2 = tPhysic:getJoint(tShapeWheel2) motorSpeed = 500 direction_car = 0 function onKeyDown(key) if mbm.getKeyCode('left') == key then direction_car = 1 elseif mbm.getKeyCode('right') == key then direction_car = -1 end end function onKeyUp(key) if mbm.getKeyCode('left') == key or mbm.getKeyCode('right') == key then direction_car = 0 end end function onLoop(delta) tShapCar.tJointWheel1:setMotorSpeed(motorSpeed * direction_car) tShapCar.tJointWheel2:setMotorSpeed(motorSpeed * direction_car) end .. figure:: _static/box_2d_joint_wheel.gif :align: center :figclass: align-center Wheel joint Joint methods ^^^^^^^^^^^^^ .. Note:: Not all :ref:`joint ` has the same methods, each :ref:`joint ` has its particularity. Active options ^^^^^^^^^^^^^^ .. data:: isActive() :noindex: Available for :ref:`all joints ` Check if both bodies are active given the joint. :return: ``boolean`` - *Both bodies are active?* *Example:* .. code-block:: lua local active = tJoint:isActive() .. data:: setActive(boolean value) :noindex: Available for :ref:`all joints ` Set active option for both bodies given the joint. :param boolean: ``value`` - *Set Active for both bodies* *Example:* .. code-block:: lua tJoint:setActive(true) Angular offset options ^^^^^^^^^^^^^^^^^^^^^^ .. data:: getAngularOffset() Available for :ref:`motor `. :return: ``number`` - *angular offset* *Example:* .. code-block:: lua local angular_offset = tJoint:getAngularOffset() .. data:: setAngularOffset(number angular_offset) Available for :ref:`motor `. :param number: **angular_offset**. *Example:* .. code-block:: lua local angular_offset = math.rad(10) tJoint:setAngularOffset(angular_offset) Anchor options ^^^^^^^^^^^^^^^ .. data:: getAnchorA() | Available for :ref:`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:* .. code-block:: lua local x,y = tJoint:getAnchorA() .. data:: getAnchorB() | Available for :ref:`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:* .. code-block:: lua local x,y = tJoint:getAnchorB() Correction factor options ^^^^^^^^^^^^^^^^^^^^^^^^^ .. data:: getCorrectionFactor() Available for :ref:`motor `. :return: ``number`` - *correction factor in range [0,1]* *Example:* .. code-block:: lua local correction = tJoint:getCorrectionFactor() .. data:: setCorrectionFactor(table joint, number correction_factor) Available for :ref:`motor ` :param number: **correction factor in range [0,1]** *Example:* .. code-block:: lua local correction_factor = 0.5 tJoint:setCorrectionFactor(correction_factor) Damping ratio options ^^^^^^^^^^^^^^^^^^^^^ .. data:: getDampingRatio() Available for :ref:`distance ` , :ref:`gear ` , :ref:`wheel `, :ref:`weld ` . :return: ``number`` - *Damping ratio* *Example:* .. code-block:: lua local damping_ratio = tJoint:getDampingRatio() .. data:: setDampingRatio(number damping_ratio) Available for :ref:`distance ` , :ref:`gear ` , :ref:`wheel `, :ref:`weld ` . :param number: **damping ratio**. *Example:* .. code-block:: lua local damping_ratio = 2 tJoint:setDampingRatio(damping_ratio) Destroy joint ^^^^^^^^^^^^^ .. data:: destroyJoint(tBody) :param renderizable: **body**. *Example:* .. code-block:: lua tPhysic:destroyJoint(tBody) .. Note:: | The engine will destroy the joint in the next cycle. | :guilabel:`destroyJoint` is only available for :ref:`box2d ` instance. It is not available for joint table. Force options ^^^^^^^^^^^^^ .. data:: getMaxForce() Available for :ref:`mouse `, :ref:`friction `, :ref:`motor `, :ref:`prismatic `. Max motor force for :ref:`prismatic `. :return: ``number`` - **maximum friction force in newton**. *Example:* .. code-block:: lua local maximum_friction_force = tJoint:getMaxForce() .. data:: setMaxForce(number max_friction_force) Available for :ref:`mouse `, :ref:`friction `, :ref:`motor `, :ref:`prismatic `. Max motor force for :ref:`prismatic `.Motor options joint :param number: **maximum friction force in newton**. *Example:* .. code-block:: lua local max_friction_force = 10 tJoint:setMaxForce(max_friction_force) Frequency options ^^^^^^^^^^^^^^^^^ .. data:: setFrequencyHz(number hertz) Available for :ref:`distance ` , :ref:`wheel `, :ref:`weld ` . :param number: **hertz**. *Example:* .. code-block:: lua local hertz = 30 tJoint:setFrequencyHz(hertz) .. data:: getFrequencyHz() Available for :ref:`distance ` , :ref:`wheel `, :ref:`weld ` . :return: ``number`` - *hertz* *Example:* .. code-block:: lua local hertz = tJoint:getFrequencyHz() .. _get_joint_box2d: Get joint ^^^^^^^^^ .. data:: getJoint(tBody,number * absolute_index) Retrieve a :ref:`joint ` previously created passing any of body used to create th joint through the method :ref:`joint ` and the absolute index (not mandatory). :param renderizable: **body**. :param number: **absolute index** of the joint in the engine. (this index can be invalid after destroying joint). :return: ``table`` - :ref:`joint ` *Example:* .. code-block:: lua tJoint = tPhysic:getJoint(tBody,indexMyJoint) .. Note:: Retrieve a :ref:`joint ` previously created using :ref:`box2d ` instance. Length options ^^^^^^^^^^^^^^ .. data:: getLength() Available for :ref:`distance ` , :ref:`rope ` . Max length for :ref:`rope ` . :return: ``number`` - *length* for :ref:`distance ` or *max length* for :ref:`rope ` . *Example:* .. code-block:: lua local length = tJoint:getLength() .. data:: setLength() Available for :ref:`distance ` , :ref:`rope ` . Max length for :ref:`rope ` . :param number: *length* for :ref:`distance ` or *max length* for :ref:`rope ` . *Example:* .. code-block:: lua local length = 10 tJoint:setLength(length) Limit options ^^^^^^^^^^^^^ .. data:: enableLimit(boolean value) Available for :ref:`revolute `, :ref:`prismatic `. :param boolean: **value**. *Example:* .. code-block:: lua local enable = true tJoint:enableLimit(enable) .. data:: getLimits() Available for :ref:`revolute `, :ref:`prismatic `. :return: ``number`` *lower* - ``number`` - *upper* *Example:* .. code-block:: lua local lower, upper = tJoint:getLimits() .. data:: setLimits(number lower, number upper) Available for :ref:`revolute `, :ref:`prismatic `. :param number: **lower**. :param number: **upper**. *Example:* .. code-block:: lua local lower, upper = 10, 10 tJoint:setLimits(lower,upper) Linear offset options ^^^^^^^^^^^^^^^^^^^^^ .. data:: getLinearOffset() Available for :ref:`motor `. :return: ``number`` *x* - ``number`` - *y* (Frame A in Meters). *Example:* .. code-block:: lua local x,y = tJoint:getLinearOffset() .. data:: setLinearOffset(number x, number y) Available for :ref:`motor ` :param number: **x** (Frame A in Meters). :param number: **y** (Frame A in Meters). *Example:* .. code-block:: lua local x,y = 10,15 tJoint:setLinearOffset(x,y) Motor options ^^^^^^^^^^^^^ .. data:: getMotorSpeed() Available for :ref:`revolute `, :ref:`prismatic `, :ref:`wheel `. :return: ``number`` - **speed** in radian per second. *Example:* .. code-block:: lua local motor_speed_rad = tJoint:getMotorSpeed() -- speed in radian per second .. data:: setMotorSpeed(number speed) Available for :ref:`revolute `, :ref:`prismatic `, :ref:`wheel `. :param number: **speed** in radian per second. *Example:* .. code-block:: lua local speed = math.rad(360) tJoint:setMotorSpeed(speed) .. data:: getMaxMotorTorque() Available for :ref:`revolute `, :ref:`wheel `, :ref:`motor ` :return: ``number`` - *max motor torque* *Example:* .. code-block:: lua local max_torque = tJoint:getMaxMotorTorque() .. data:: setMaxMotorTorque(number max_torque) Available for :ref:`revolute `, :ref:`wheel `, :ref:`motor ` :param number: **max torque**. *Example:* .. code-block:: lua local torque = 5 tJoint:setMaxMotorTorque(torque) .. data:: enableMotor(boolean value) Available for :ref:`revolute `, :ref:`prismatic `, :ref:`wheel `. :param boolean: **value**. *Example:* .. code-block:: lua local enable = true tJoint:enableMotor(enable) Reaction options ^^^^^^^^^^^^^^^^ .. data:: getReactionForce(number inv_delta) Available for :ref:`all joints ` :param number: **inv_delta**. :return: ``number`` *x* - ``number`` - *y* reaction force on body B at the joint anchor in Newtons. *Example:* .. code-block:: lua local inv_delta = 1/60 local x,y = tJoint:getReactionForce(inv_delta) .. data:: getReactionTorque(number inv_delta) Available for :ref:`all joints ` :param number: **inv_delta**. :return: ``number`` - *reaction torque on body B in N x m* *Example:* .. code-block:: lua local inv_delta = 1/60 local reaction_torque = tJoint:getReactionTorque(inv_delta) Target options ^^^^^^^^^^^^^^ .. data:: getTarget() | Available for :ref:`mouse `. | You should consider the :ref:`box2d scale ` to this method to transform to ``2dw`` coordinates. :return: ``number`` *x* - ``number`` - *y* *Example:* .. code-block:: lua local box2d_scale = tPhysic:getScale() local x,y = tJoint:getTarget() x,y = x * box2d_scale, y * box2d_scale .. data:: setTarget(number x, number y) | Available for :ref:`mouse `. | You should consider the :ref:`box2d scale ` to this method. :param number: **x**. :param number: **y**. *Example:* .. code-block:: lua -- 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