lua.box2d
local box2d=require("box2d")
We use box2d as the local name of this library.
A lua binding to the box2d physics library see https://box2d.org/ for more documentation on how box2d works.
lua.box2d.body.aabb
xa,ya,xb,yb = body:aabb()
Get body aabb as stream of numbers, lower bounds first then upper.
Note this value has to be calculated.
lua.box2d.body.acceleration
body:acceleration()
body:acceleration(x,y)
body:acceleration(x,y,r)
body:acceleration(nil,nil,r)
set body acceleration, which is to say we set the body force multiplied by mass or rotational inertia. Note that this will not work on a 0 mass body, I think you have to fake a mass on a body with no shapes first.
x,y is acceleration per second applied to center mass, will be cleared if nil
r is rotational acceleration per second in radians , will be cleared if nil
This will replace force and acceleration and as force is applied then cleared during a step, this needs to be set for every step.
lua.box2d.body.awake
b = body:awake()
b = body:awake(b)
get/set body sleeping state.
lua.box2d.body.convert
x,y = body:convert(x,y,conversion)
conversion must be one of the following strings indicating how the input x,y should be transformed into the output x,y
x,y = body:convert(x,y,"point_local_to_world")
x,y = body:convert(x,y,"point_world_to_local")
x,y = body:convert(x,y,"vector_local_to_world")
x,y = body:convert(x,y,"vector_world_to_local")
x,y = body:convert(x,y,"point_local_to_velocity")
x,y = body:convert(x,y,"point_world_to_velocity")
convert x,y between various spaces.
lua.box2d.body.destroy
body:destroy()
Destroy the body and all sub objects (shapes)
lua.box2d.body.force
body:force()
body:force(x,y)
body:force(x,y,r)
body:force(nil,nil,r)
set body force , note that this does not return the current force and calling it without any values will clear the current force.
x,y is force applied to center mass, will be cleared if nil
r is torque , will be cleared if nil
This will replace force and acceleration and as force is applied then cleared during a step, this needs to be set for every step.
lua.box2d.body.get
vars = body:get()
Get all body variables in a table.
lua.box2d.body.info
info = body:info()
This returns the def table used to create the body along with as much updated information as we have available, mostly intended as a debugging aid.
This is the actual def table (some values are hard to query later) so if you edit it or if you create this object using a non unique def table things can get strange.
lua.box2d.body.mass
mass , rotationalInertia , x,y = body:mass( mass , rotationalInertia , x,y )
mass = ( body:mass(mass) )
get/set mass values, all values are optional but x,y must be a pair. Unset values will remain unchanged.
x,y is center of mass
We return 4 values but as the first one is mass you can simply ignore the rest by wrapping the function in ()
Since adding shapes will auto generate these values, be aware that you will be fighting auto mass generation when setting this value.
Adding shapes or changing the body type will auto generate these values.
lua.box2d.body.set
body:set(vars)
Set all body variables from a table.
lua.box2d.body.transform
x,y,r = body:transform()
x,y,r = body:transform(x,y,r)
get/set body transform
lua.box2d.body.type
btype = body:type()
btype = body:type(btype)
get/set body type. btype is a string, Possible values are
static
kinematic
dynamic
lua.box2d.body.velocity
x,y,r = body:velocity()
x,y,r = body:velocity(x,y,r)
get/set body velocity
lua.box2d.get
vars = box2d.get()
Get all box2d variables in a table. Returned table keys are.
lengthUnitsPerMeter
see box2d.set for more information.
lua.box2d.info
info = box2d.info()
Get all box2d information in a table. Returned table keys are.
version
A table containing 3 values
byteCount
Internal memory use.
This also includes everything returned by box2d.get
lua.box2d.joint.destroy
joint:destroy()
Destroy the joint and all sub objects (none)
lua.box2d.joint.get
vars = joint:get()
Get all joint variables in a table.
lua.box2d.joint.info
info = joint:info()
This returns the def table used to create the joint along with as much updated information as we have available, mostly intended as a debugging aid.
This is the actual def table (some values are hard to query later) so if you edit it or if you create this object using a non unique def table things can get strange.
lua.box2d.joint.set
joint:set(vars)
Set all joint variables from a table.
lua.box2d.set
box2d.set(vars)
Set all box2d variables from a table. Possible table keys are.
LengthUnitsPerMeter
Units per meter, should be set first before creating a world.
Defaults to 1.
Obviously points and vectors should be divided by units to get their value in meters but slightly less obviously density values end up getting multiplied by units squared since they are area related.
What that means is if you are thinking in meters eg you want to set gravity to 10m/s you will need to multiply it by units. Density which would normally be 1 should be 1/(units^2) in order to keep the results close to defaults.
Note that Box2d recommends not changing this, be we cool, yeah?
lua.box2d.shape.aabb
xa,ya,xb,yb = shape:aabb()
Get shapes aabb as stream of numbers, lower bounds first then upper.
lua.box2d.shape.convert
x,y = shape:convert(x,y,conversion)
conversion must be one of the following strings indicating how the input x,y should be transformed into the output x,y
x,y = shape:convert(x,y,"closest")
convert x,y point in world space into x,y closest point on shape.
lua.box2d.shape.destroy
shape:destroy()
Destroy the shape and all sub objects (none)
lua.box2d.shape.get
vars = shape:get()
Get all shape variables in a table.
lua.box2d.shape.info
info = shape:info()
This returns the def table used to create the shape along with as much updated information as we have available, mostly intended as a debugging aid.
This is the actual def table (some values are hard to query later) so if you edit it or if you create this object using a non unique def table things can get strange.
lua.box2d.shape.set
shape:set(vars)
Set all shape variables from a table.
lua.box2d.world
world=box2d.world(def)
Create the world you will be simulating physics in.
def contains the values that you can set in a b2WorldDef and must be a unique table as it will be retained.
All of these are optional so can be nil.
Vectors are a table containing { x , y } values. This may also be a fake table created by lua meta.
Booleans should be true or false
gravity
restitutionThreshold
hitEventThreshold
contactHertz
contactDampingRatio
contactSpeed
maximumLinearSpeed
enableSleep
enableContinuous
enableContactSoftening
lua.box2d.world.bits
bits=world:bits(name)
bits=world:bits(name,{mask=0xfffffffffffff,bits=0x0000000000001,group=0})
bits=world:bits(name,false)
get/set named bits, to help with keeping all your bitmasks in one place so you don't get yourself confuzzled.
bits is must be a table containing mask, bits and group then instead of setting these numbers explicitly we can use this name in shape creation or casting, anywhere a filter is expected.
This helper code adds the following logic to shape creation etc
if filter is set then get bits using world:bits(filter) then
filter_categoryBits will be set from bits.bits if nil
filter_maskBits will be set from bits.mask if nil
filter_groupIndex will be set from bits.group if nil
You probably do not want to create default values for these values using world:defaults as these will not be replace by this helper.
Pass in false to unset the named bits.
If bits does not exist then we will return the default values of {mask=0xfffffffffffff,bits=0x0000000000001,group=0} which can be modified by setting the bits named "default" to whatever you want.
Since this default is always available you can use filter="default" in shape creation to use these default values.
Note that 0xfffffffffffff (13 hex digits) is an integer that fits safely in a double and you should not use any more bits.
lua.box2d.world.body
body=world:body(def)
Create a body in the world.
def contains the values that you can set in a b2BodyDef and must be a unique table as it will be retained.
All of these are optional so can be nil.
Vectors are a table containing values in the integer indexes. This may also be a fake table created by lua meta.
Values with _ are sub structs eg motionLocks_linearX is motionLocks.linearX
Booleans should be true or false
name is a string that should be 31 chars or less and is only used to
help with debugging.
type is a string and must be "static" or "kinematic" or "dynamic"
allowFastRotation
angularDamping
angularVelocity
enableSleep
motionLocks_linearX
motionLocks_linearY
motionLocks_angularZ
gravityScale
isAwake
isBullet
isEnabled
linearDamping
linearVelocity
name
position
rotation
sleepThreshold
type
lua.box2d.world.body.shape
shape=body:shape(def)
Create a shape in the body.
def contains the values that you can set in a b2ShapeDef and must be a unique table as it will be retained.
All of these are optional so can be nil.
Vectors are a table containing { x , y } values. This may also be a fake table created by lua meta.
Booleans should be true or false
Minor safety issue regarding filter bitmasks since lua(jit) uses doubles these bit masks should only use 52 bits not 64 so the integers can fit safely into a double. When using hex the top 3 nibbles should always be 0 like so 0x000fffffffffffff that is 13 Fs if you are counting.
density
enableContactEvents
enableHitEvents
enablePreSolveEvents
enableSensorEvents
filter
invokeContactCreation
isSensor
material_customColor
material_friction
material_restitution
material_rollingResistance
material_tangentSpeed
material_userMaterialId
updateBodyMass
if def.shape=="circle" then def also contains the values that you can set in a b2Circle
center
radius
if def.shape=="segment" then def also contains the values that you can set in a b2Segment
point1
point2
if def.shape=="capsule" then def also contains the values that you can set in a b2Capsule
center1
center2
radius
if def.shape=="box" then def also contains the values that you can set in a b2Polygon using b2MakeOffsetRoundedBox
halfWidth
halfHeight
center
rotation
radius
lua.box2d.world.body_events
events = world:body_events()
events = world:body_events(events)
get body events generated by the last step
lua.box2d.world.cast
hits = world:cast(ray)
if ray.points is set then this is a polygon shape cast, otherwise this is an ray cast.
cast a ray and return an array of hits
ray.points
Tightly packed array of points for the shape. Maximum number of points
is B2_MAX_POLYGON_VERTICES (8) To cast a circle shape, just use a
radius and a single point at the origin.
ray.radius
Radius of the shape to cast, does not work unless you also set points.
ray.origin
Starting world point of ray
ray.translation
The ray to cast
ray.filter_categoryBits
ray.filter_maskBits
ray.filter
Filter masks, ray.filter is a previously set name that we will convert
using world:bits(name) into filter_categoryBits and filter_maskBits
unless they are already set.
hit=hits[1]
hit=hits[2]
etc
Returned hits which are sorted by fraction from low to high.
Initial overlaps are returned with a fraction of 0 and normal of 0. If you want the first actual hit you should ignore these and get the first hit with a non zero normal.
If hits[1] is nil then there where no hits.
hit.shapeID
BoxID of the shape we hit.
hit.shape
Table of the shape we hit. Filled in from shapeID for your convenience,
if somehow (?) shapeID is invalid then this will be nil. Shapes have a
uid that you can use to map shapes to game objects.
hit.fraction
0-1 value, indicating how far from the origin the ray traveled.
hit.point
Table containing world coordinates of the hit point.
hit.normal
Table containing shape normal at the hit point.
hits.leafVisits
hits.nodeVisits
Contain extra debug information
lua.box2d.world.contact_events
events = world:contact_events()
events = world:contact_events(events)
get contact events generated by the last step
lua.box2d.world.defaults
cache=world:defaults(name)
cache=world:defaults(name,def)
Remember default values in the world cache, this is intended for generic body/shape/joint creation.
Returns the current def cache for the name.
The def table will be copied ( top level only ) into a cache of the given values adding or replacing them.
if def table is nil then the current cached values will be cleared.
For example to cache a constant density value ( because you changed the global units per meters )
world:defaults("shape",{density=1/256})
When shapes are created they will automatically use the "shape" cache to fill in missing values. Same for "body" and "joint" caches.
You can also use this to fill in special object defaults like so.
world:defaults("shape_bouncy",{material_restitution=1})
...
body:shape(world:fill({...},"shape_bouncy"))
lua.box2d.world.destroy
world:destroy()
Destroy the world and all sub objects ( body , joint , shape )
lua.box2d.world.fill
def=world:fill(def,name)
Set previously cached default values under name into the def table unless a value already exists. This is intended to be used in body/shape/joint creation as a way of applying generic settings for each.
def may be nil in which case a new table is created and returned,
If we do not have any cached values for name then def will not be altered.
This is automatically called to fill in body/shape/joint values that have previously been cached with the generic name "body"."shape","joint" when creating a new body/shape/joint
You may call it explicitly for slightly less generic defaults, eg
body:shape( world:fill({...},"shape_special") )
Note that when creating objects def should always be a new table as it will be kept within the new object and returned by the info function.
lua.box2d.world.fills
def=world:fills(def,...)
Same as fill except multiple names may be given and each applied from left to right. So the left most values will have precedence and missing values will be filled in as we travel left to right.
lua.box2d.world.get
vars = world:get()
Get all world variables into a table.
lua.box2d.world.info
info = world:info()
This returns the def table used to create the world along with as much updated information as we have available, mostly intended as a debugging aid.
This is the actual def table (some values are hard to query later) so if you edit it or if you create this object using a non unique def table things can get strange.
lua.box2d.world.joint
joint=world:joint(def)
Create a joint in the world.
def contains the values that you can set in a b2jointDef and must be a unique table as it will be retained.
All of these are optional so can be nil.
Vectors are a table containing { x , y } values. This may also be a fake table created by lua meta.
Booleans should be true or false
localFrameA/B is a transform which is a vector plus a rotation in radians, so { x , y , r }
The boxid of a body ( for bodyIdA and bodyIdB ) can be found in body.boxid
bodyIdA
bodyIdB
localFrameA
localFrameB
forceThreshold
torqueThreshold
constraintHertz
constraintDampingRatio
collideConnected
if def.joint=="distance" then def also contains the values that you can set in a b2DistanceJointDef
length
enableSpring
lowerSpringForce
upperSpringForce
hertz
dampingRatio
enableLimit
minLength
maxLength
enableMotor
maxMotorForce
motorSpeed
if def.joint=="motor" then def also contains the values that you can set in a b2MotorJointDef
linearVelocity
maxVelocityForce
angularVelocity
maxVelocityTorque
linearHertz
linearDampingRatio
maxSpringForce
angularHertz
angularDampingRatio
maxSpringTorque
if def.joint=="filter" then def also contains the values that you can set in a b2FilterJointDef
-- no extra values just those found in b2jointDef
if def.joint=="prismatic" then def also contains the values that you can set in a b2PrismaticJointDef
enableSpring
hertz
dampingRatio
targetTranslation
enableLimit
lowerTranslation
upperTranslation
enableMotor
maxMotorForce
motorSpeed
if def.joint=="revolute" then def also contains the values that you can set in a b2RevoluteJointDef
targetAngle
enableSpring
hertz
dampingRatio
enableLimit
lowerAngle
upperAngle
enableMotor
maxMotorTorque
motorSpeed
if def.joint=="weld" then def also contains the values that you can set in a b2WeldJointDef
linearHertz
angularHertz
linearDampingRatio
angularDampingRatio
if def.joint=="wheel" then def also contains the values that you can set in a b2WheelJointDef
enableSpring
hertz
dampingRatio
enableLimit
lowerTranslation
upperTranslation
enableMotor
maxMotorTorque
motorSpeed
lua.box2d.world.overlap
overlaps = world:overlap(shape)
if shape.points is set then this is a polygon shape overlap, otherwise this is an aabb overlap.
Get all shapes overlapping aabb or shape , I believe this might return
some shapes that do not actually overlap the given box so should
probably double check.
shape.points
Tightly packed array of points for the shape. Maximum number of points is B2_MAX_POLYGON_VERTICES (8) To cast a circle shape, just use a radius and a single point at the origin.
shape.radius
Radius of the shape to cast, does not work with aabb.
shape.lowerBound
shape.upperBound
Lower and upper aabb vectors ( will be added to origin ) this is
ignored if shape.points is set.
shape.origin
Origin vector of shape
shape.filter_categoryBits
shape.filter_maskBits
Filter masks
overlaps.shapeIds
An array of shapeIds
overlaps.shapes
An array of shapes
overlaps.leafVisits
overlaps.nodeVisits
Extra debug information
lua.box2d.world.prepare_events
events = world:prepare_events()
events = world:prepare_events(events)
Prepare a table to be filled with all events.
events.uids
Lookup table by uid of events by body.uid or shape.uid A single event may appear multiple times but it will be the same table.
events.all
A list of all events regardless of a uid being set.
events:insert(event,ita,itb)
Helper function to place an event in uids and all. ita and itb may be nil or a shape or a body. We look for ita.uid and itb.uid to fill the uids map.
events.contact_cache
cache of contacts for multiple calls to events.contact to reuse
events:contact(id)
Get contact information from a contact id, we cache results in events.contact_cache so multiple calls will return the same table so is safe to call multiple times with the same id.
A contact is a large chunk of possibly unwanted data so has to be explicitly requested later using the contactId provided by contact events.
May possibly be nil if an invalid contact ID, eg this is old data and you called world:step again and created new contacts.
for event in events:iterate(uid) do ... end
A simple iterator function for the events associated with the given uid, or all events if uid is nil.
lua.box2d.world.sensor_events
events = world:sensor_events()
events = world:sensor_events(events)
get sensor events generated by the last step
lua.box2d.world.set
world:set(vars)
Set all world variables from a table.
lua.box2d.world.step
world:step(seconds,steps)
Advance the world "seconds" through time using "steps" number of discreet sub steps.
Generally the simulation expects (1/seconds)*steps to be 240 ish. So 240 substeps per second. 1/60 and 4 are the defaults.