PhysicsSystem¶
Inherits: SubSystem
2D (Box2D) and 3D (Jolt) simulation. scene:getPhysicsSystem().
Properties¶
| Type | Name | Default | Languages |
|---|---|---|---|
| Vector2 | gravity2D | (0,-9.81) |
C++ | Lua |
| Vector3 | gravity3D | (0,-9.81,0) |
C++ | Lua |
| Vector3 | gravity | (0,-9.81,0) |
C++ | Lua |
| float | pointsToMeterScale2D | 64.0 |
C++ | Lua |
| bool | lock3DBodies | true |
C++ | Lua |
| bool | interpolation | true |
C++ | Lua |
| bool | steppingWorld3D | false |
C++ | Lua (read-only) |
gravity2D and gravity3D set each world's gravity independently (m/s²); the legacy gravity / setGravity(...) sets both worlds at once and reads back the 3D value. The same values are exposed directly on Scene — scene.gravity2D / scene.gravity3D — which is what the editor's scene Physics section edits and saves.
lock3DBodies decides whether 3D body access takes Jolt's body locks. Leave it on unless
you drive the world from a worker thread. It is ignored while steppingWorld3D is true,
since the step already holds those locks.
interpolation draws each 2D and 3D body between its poses at the last two fixed steps,
so bodies move smoothly at frame rates above the step rate. The entity's transform then
trails the body by less than one step: read the body pose for gameplay and the transform
for what follows the body on screen. Off, the transform holds the body pose of the last
step. See Smooth motion between steps.
steppingWorld3D is true while the 3D world simulates, which is exactly when the 3D
callbacks below run.
Events¶
2D: beginContact2D, endContact2D, hitContact2D, sensor contacts, preSolve2D, shouldCollide2D
3D: onContactAdded3D, onContactPersisted3D, onContactRemoved3D, onBodyActivated3D, onBodyDeactivated3D, shouldCollide3D
See Events. Use onFixedUpdate for forces.
A filter callback must return a value
preSolve2D, shouldCollide2D, and shouldCollide3D are the events whose return
value is read. A Lua handler that falls off the end returns nil, which is read as
false and rejects the contact. The true default only applies when nothing is
subscribed at all, so always end the handler with an explicit return.
Inside a 3D callback¶
3D events fire while Jolt is stepping, on a thread that already holds the body locks:
- Reading and moving bodies is fine — velocity, position, ray casts. The engine uses Jolt's lock-free interfaces for the whole step.
- Creating a body or joint is refused and logged; the next update retries it.
- Destroying one is queued and applied when the step ends, so removing a
Body3DComponentfrom a callback tears its body down properly.
Anything else belongs in onUpdate or onFixedUpdate. Check steppingWorld3D when a
helper can be called from both places.