Read and tune the Bullet dynamics world owned by the current collection. Defold remains responsible for world lifetime, stepping, collision objects, callbacks, and debug drawing.
World and collision-object values returned by this API are borrowed, generational handles. They become invalid when their collection or owning game object is deleted and must not be retained as native pointers.
All positions, distances, translations, dimensions and contact distances use
Defold world units. The binding converts them using physics.scale. Rotations
and unit normals are not scaled. Query functions refresh Bullet broadphase
AABBs before execution, so collision-object transform changes are visible.
Query filters are optional tables with these fields:
category_bits65535mask_bits65535include_triggerstrueignorereport_initial_overlapsfalsereport_initial_overlaps is a bullet3d.world query option only. It does
not change physics.raycast() or either Box2D backend.
Category and mask checks are reciprocal: the query category must match the object's mask and the object's category must match the query mask.
Temporary query shapes use the same geometry fields as
[ref:bullet3d.shape.get_shape]:
a sphere has type and diameter, a box has type and dimensions, a
Y-axis capsule has type, diameter and height, and a convex hull has
type and a vertices array with at least four vector3 values. The type
is one of the bullet3d.shape.SHAPE_TYPE_* constants. Every shape can specify
position and rotation; their defaults are zero and the identity rotation.
Cast shapes can also specify target_rotation, which defaults to rotation.
Capsule height is the length of the cylindrical middle section; total
end-to-end height is height + diameter. Query sizes are always expressed
in Defold world units. A table returned by bullet3d.shape.get_shape can be
reused directly after adding the desired query transform fields.
Hull vertices describe a convex hull; concave input is convexified by Bullet.
All query vectors and scalar sizes must be finite. Diameters, dimensions and
capsule heights must be greater than zero; hulls require at least four finite
vertices. Cast translations must be finite and non-zero. Query rotations
must be finite, non-zero quaternions and are normalized by the binding. AABB
lower bounds must not exceed their corresponding upper bounds.
Overlap and enumeration results are arrays of btCollisionObject handles.
Cast results are tables containing object, point, normal, fraction,
initial_overlap, and inside. shape_index is present when Bullet reports
a compound child and is one-based. Cast arrays are sorted by ascending
fraction. fraction is in [0, 1] along the supplied translation. For native
hits, normal is the hit object's outward unit surface normal; synthesized
initial-overlap hits use a zero normal. inside is true for a synthesized
ray-origin hit when Bullet reports signed contact distance less than or equal
to zero. It denotes initial contact or penetration rather than strict
geometric containment, and exact-surface cases follow Bullet's contact
tolerance. Shape-cast initial overlaps set only initial_overlap.
Contact results contain object_a, object_b, position_a, position_b,
normal_on_b, and signed distance. Positions are points on their named
objects, and normal_on_b points from object B toward object A. A negative
distance is penetration and a small positive distance is Bullet's contact
margin. Object order is always normalized to the order supplied by the caller.
max_results is optional. Zero or omission means unlimited results. A
negative value is an error. Broadphase overlaps, native world enumeration,
contacts, and equal-fraction cast hits have unspecified order. A capped query
can therefore return a different equal-priority subset after world changes.
Synchronous queries execute immediately and do not advance simulation.
Async casts are deferred until after the next physics step. They execute on
the main thread rather than a worker thread, and all queued casts for one
world share one broadphase AABB refresh. Every cast in the batch completes
before any callback runs, so callback mutations cannot affect other query
computations in that batch. Deferral avoids blocking the Lua call site but
does not remove the cast work from the frame.
Native fraction-zero cast callbacks are suppressed. Starting overlaps are
omitted by default, or reported through the exact, deduplicated synthesis
enabled by report_initial_overlaps; this avoids direction-dependent Bullet
results for casts that start touching or penetrating another object.
Version: alpha
| FUNCTIONS | |
|---|---|
| bullet3d.world.cast_ray() | Cast a ray |
| bullet3d.world.cast_ray_async() | Cast a ray asynchronously |
| bullet3d.world.cast_ray_closest() | Cast a ray and return the closest hit |
| bullet3d.world.cast_shape() | Cast a convex shape |
| bullet3d.world.cast_shape_async() | Cast a convex shape asynchronously |
| bullet3d.world.cast_shape_closest() | Cast a convex shape and return the closest hit |
| bullet3d.world.contact_pair_test() | Test a collision-object pair |
| bullet3d.world.contact_test() | Test one collision object against the world |
| bullet3d.world.get_collision_object_count() | Get the number of collision objects in the world |
| bullet3d.world.get_collision_objects() | Enumerate collision objects |
| bullet3d.world.get_gravity() | Get world gravity |
| bullet3d.world.is_valid() | Test whether a world handle is valid |
| bullet3d.world.overlap_aabb() | Find broadphase AABB overlaps |
| bullet3d.world.overlap_point() | Find collision objects containing a point |
| bullet3d.world.overlap_shape() | Find collision objects overlapping a convex shape |
| bullet3d.world.set_gravity() | Set world gravity |
bullet3d.world.cast_ray(world,origin,translation,filter,max_results)
Casts immediately from origin to origin + translation and returns all
matching hits sorted by fraction. Translation must be non-zero.
Bullet 2.77 normally does not report a ray whose start and end are both inside
the same convex hull. Set filter.report_initial_overlaps = true to perform
an exact point-overlap test at the origin and synthesize one deduplicated hit
per initially touching or overlapping object with fraction = 0, zero normal,
point = origin, initial_overlap = true, and inside = true. The point is
the query origin, not a surface contact. This explicitly supports the
inside-hull behavior requested by issue #5348. Fraction-zero native callbacks
and starting overlaps are suppressed when the option is false.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
origin |
vector3 |
ray origin in world space |
translation |
vector3 |
non-zero ray displacement in world units |
[filter] |
table |
query filter |
[max_results] |
number |
maximum sorted hits, or zero for all |
RETURNS
hits |
table |
cast-result array sorted by ascending fraction |
bullet3d.world.cast_ray_async(world,origin,translation,filter,max_results,callback)
Queues the same ray query as bullet3d.world.cast_ray and returns without
executing it. After the next physics step, callback(self, hits) receives the
cast-result array sorted by fraction. The query observes post-step world state.
It is deferred on the main thread, not executed concurrently; use it to move
work out of the current Lua call and to query the stepped state, not as a
guarantee of lower total CPU time. Queued casts for the same world share one
broadphase AABB refresh and all finish before their callbacks begin.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
origin |
vector3 |
ray origin in world space |
translation |
vector3 |
non-zero ray displacement in world units |
[filter] |
table |
query filter |
[max_results] |
number |
maximum sorted hits, or zero for all |
callback |
function |
function called as callback(self, hits)
|
EXAMPLES
Queue a downward cast and inspect only the closest non-trigger hit:bullet3d.world.cast_ray_async(
bullet3d.get_world(),
go.get_world_position(),
vmath.vector3(0, -100, 0),
{ include_triggers = false },
1,
function(self, hits)
if hits[1] then
print("hit", hits[1].object)
end
end)
bullet3d.world.cast_ray_closest(world,origin,translation,filter)
Equivalent to bullet3d.world.cast_ray with one result, but returns the
hit table directly or nil on a miss.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
origin |
vector3 |
ray origin in world space |
translation |
vector3 |
non-zero ray displacement in world units |
[filter] |
table |
query filter |
RETURNS
hit |
tablenil |
closest cast-result table, or nil on a miss |
EXAMPLES
Cast downward and report the closest non-trigger hit:function init(self)
local world = bullet3d.get_world()
local origin = go.get_world_position()
local translation = vmath.vector3(0, -100, 0)
local filter = { include_triggers = false }
local hit = bullet3d.world.cast_ray_closest(
world, origin, translation, filter)
if hit then
local distance = vmath.length(translation) * hit.fraction
print("hit", hit.object, "after", distance, "units")
end
end
bullet3d.world.cast_shape(world,shape,translation,filter,max_results)
Sweeps the temporary shape from shape.position by translation, while
interpolating from shape.rotation to shape.target_rotation. Translation
must be non-zero. The query executes immediately and returns all matching hits
sorted by fraction. Bullet's convex sweep supports only convex query shapes.
When filter.report_initial_overlaps is true, an exact contact test at the
starting transform synthesizes one deduplicated hit per overlapping object
with fraction = 0, point = shape.position, zero normal,
initial_overlap = true, and inside = false. The point is the query-shape
origin, not a surface contact, and the result does not report penetration depth.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
shape |
table |
convex query-shape table with optional target rotation |
translation |
vector3 |
non-zero sweep displacement in world units |
[filter] |
table |
query filter |
[max_results] |
number |
maximum sorted hits, or zero for all |
RETURNS
hits |
table |
cast-result array sorted by ascending fraction |
bullet3d.world.cast_shape_async(world,shape,translation,filter,max_results,callback)
Queues the same convex sweep as bullet3d.world.cast_shape and returns
without executing it. After the next physics step, callback(self, hits)
receives the sorted cast-result array from the post-step world state. The
operation is deferred on the main thread rather than run concurrently. All
queued casts for one world share one broadphase AABB refresh and all finish
before their callbacks begin.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
shape |
table |
convex query-shape table with optional target rotation |
translation |
vector3 |
non-zero sweep displacement in world units |
[filter] |
table |
query filter |
[max_results] |
number |
maximum sorted hits, or zero for all |
callback |
function |
function called as callback(self, hits)
|
bullet3d.world.cast_shape_closest(world,shape,translation,filter)
Equivalent to bullet3d.world.cast_shape with one result, but returns
the hit table directly or nil on a miss.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
shape |
table |
convex query-shape table with optional target rotation |
translation |
vector3 |
non-zero sweep displacement in world units |
[filter] |
table |
query filter |
RETURNS
hit |
tablenil |
closest cast-result table, or nil on a miss |
bullet3d.world.contact_pair_test(world,object_a,object_b,max_results)
Runs Bullet's discrete pair contact algorithm without changing the simulation.
Both borrowed handles must belong to world and must identify different
objects. The output preserves the caller's A/B order even when Bullet's
internal manifold order is reversed. Collision filters are not applied to an
explicitly selected pair.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
object_a |
btCollisionObject |
first collision object in the world |
object_b |
btCollisionObject |
different second collision object in the world |
[max_results] |
number |
maximum number of contact points, or zero for all |
RETURNS
contacts |
table |
normalized contact-result array |
bullet3d.world.contact_test(world,object,filter,max_results)
Runs Bullet's discrete contact test between object and matching objects in
the same world. The supplied object is always object_a in returned contacts.
The borrowed collision-object handle must belong to world. Bullet may return
several contact points for one object pair and may include small positive
contact-margin distances.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
object |
btCollisionObject |
collision object belonging to the world |
[filter] |
table |
filter applied to candidate object_b values
|
[max_results] |
number |
maximum number of contact points, or zero for all |
RETURNS
contacts |
table |
normalized contact-result array |
EXAMPLES
Inspect current contacts for this collision object:function update(self, dt)
local world = bullet3d.get_world()
local object = bullet3d.get_collision_object("#collisionobject")
local filter = { include_triggers = false }
local contacts = bullet3d.world.contact_test(world, object, filter)
for _, contact in ipairs(contacts) do
if contact.distance < 0 then
print("penetration", -contact.distance, "against", contact.object_b)
end
end
end
bullet3d.world.get_collision_object_count(world)
Get the number of collision objects in the world
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
RETURNS
count |
number |
number of collision objects |
bullet3d.world.get_collision_objects(world,max_results)
Returns the Defold-owned collision objects currently registered in the world. Internal or unmanaged Bullet objects without Defold ownership metadata are not exposed.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
[max_results] |
number |
maximum number of results, or zero for all |
RETURNS
objects |
table |
array of collision-object handles |
bullet3d.world.get_gravity(world)
Get world gravity
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
RETURNS
gravity |
vector3 |
gravity in Defold units per second squared |
bullet3d.world.is_valid(world)
Test whether a world handle is valid
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
RETURNS
valid |
boolean |
true if the native world still exists |
bullet3d.world.overlap_aabb(world,aabb,filter,max_results)
Finds collision objects whose Bullet broadphase bounds overlap the supplied world-space AABB. This is intentionally a broadphase query and can include objects whose actual collision geometry does not intersect the box. Use bullet3d.world.overlap_point or bullet3d.world.overlap_shape for exact narrow-phase overlap tests.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
aabb |
table |
table with world-space lower and upper vector3 bounds
|
[filter] |
table |
query filter |
[max_results] |
number |
maximum number of results, or zero for all |
RETURNS
objects |
table |
array of overlapping collision-object handles |
bullet3d.world.overlap_point(world,point,filter,max_results)
Performs an exact narrow-phase test using a temporary zero-radius Bullet sphere at the world-space point. A result is returned only for a contact with signed distance less than or equal to zero, so broadphase-only false positives are removed. Results on an exact surface follow Bullet's contact tolerance.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
point |
vector3 |
point in world space |
[filter] |
table |
query filter |
[max_results] |
number |
maximum number of results, or zero for all |
RETURNS
objects |
table |
array of overlapping collision-object handles |
bullet3d.world.overlap_shape(world,shape,filter,max_results)
Performs an exact Bullet contact test for a temporary sphere, box, Y-axis capsule, or convex hull. Multiple native contact points for the same target object are deduplicated in the returned overlap array.
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
shape |
table |
convex query-shape table |
[filter] |
table |
query filter |
[max_results] |
number |
maximum number of results, or zero for all |
RETURNS
objects |
table |
array of overlapping collision-object handles |
EXAMPLES
Find non-trigger objects overlapping a two-unit sphere around this game object:function init(self)
local world = bullet3d.get_world()
local shape = {
type = bullet3d.shape.SHAPE_TYPE_SPHERE,
diameter = 2,
position = go.get_world_position(),
}
local filter = { include_triggers = false }
local overlaps = bullet3d.world.overlap_shape(world, shape, filter)
for _, object in ipairs(overlaps) do
print("overlap", object)
end
end
bullet3d.world.set_gravity(world,gravity)
Set world gravity
PARAMETERS
world |
btDiscreteDynamicsWorld |
world handle |
gravity |
vector3 |
finite gravity in Defold units per second squared |
EXAMPLES
Set gravity for the current collection's physics world:function init(self)
local world = bullet3d.get_world()
if world then
bullet3d.world.set_gravity(world, vmath.vector3(0, -9.81, 0))
end
end