Box2DPhysicsEngine class
Box2D v3.2 physics engine adapter exposing the same duck-typed API as the pure-Dart PhysicsEngine.
Drop-in replacement on native platforms — PhysicsEngineFactory.create
returns this class. The existing ECS (PhysicsSystem, PhysicsBridgeSystem)
requires no changes because both engines share the same API surface and
communicate through PhysicsBody objects.
Architecture:
Box2DWorldowns the native world + fixed-step accumulator.Box2DBodywraps each native body handle with prev/current state.- After each step,
_syncTransformsFromNativeextracts all transforms in a single FFI call into pre-allocated native buffers (zero-copy). - pollContactBeginEvents lets just_game_engine's Box2DCollisionSystem fire CollisionEvents without coupling this package to the ECS.
- registerImpactCallback routes high-velocity collisions from native worker threads to the Dart main isolate via NativeCallable.listener.
- Inheritance
-
- Object
- PhysicsEngine
- Box2DPhysicsEngine
Constructors
- Box2DPhysicsEngine({double gravityX = 0.0, double gravityY = 981.0, int subSteps = 4, int numThreads = 0})
Properties
- alpha → double
-
Render interpolation alpha from the current frame (for ECS bridge use).
no setteroverride
-
bodies
→ List<
PhysicsBody> -
Get all bodies
no setteroverride
- bodyCount → int
-
How many bodies the world holds, without copying them.
no setteroverride
- debugRender ↔ bool
-
Whether debug rendering is enabled
getter/setter pairinherited
- fixedTimestep → bool
-
Whether update sub-steps at a fixed 1/60 s. See PhysicsEngine.pureDart.
finalinherited
- gravity → Vector2
-
Global gravity vector. Default: 981 units/s² (9.81 m/s² at 1 unit = 1 cm),
matching the Box2D backend so both simulate identically.
finalinherited
- hashCode → int
-
The hash code for this object.
no setterinherited
-
joints
→ List<
JointConstraint> -
All active joints (read-only view).
no setterinherited
- numThreads → int
-
Number of native worker threads (0 → cores − 1, at most 4).
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
-
stats
→ Map<
String, dynamic> -
Lightweight physics diagnostics from the last simulation step.
no setteroverride
- subSteps → int
-
Number of Box2D sub-steps per fixed tick (4 recommended).
final
Methods
-
addBody(
PhysicsBody body) → void -
Add a PhysicsBody to the simulation.
override
-
addDistanceJoint(
PhysicsBody a, PhysicsBody b, {double? length, double? minLength, double? maxLength, double stiffness = 0.0, double damping = 0.3}) → JointConstraint -
override
-
addJoint(
JointConstraint joint) → void -
Add a joint constraint to the simulation.
inherited
-
addMouseJoint(
PhysicsBody b, Vector2 target) → JointConstraint -
inherited
-
addPrismaticJoint(
PhysicsBody a, PhysicsBody b, Offset axis) → JointConstraint -
override
-
addRevoluteJoint(
PhysicsBody a, PhysicsBody b, Offset worldAnchor) → JointConstraint -
override
-
addWeldJoint(
PhysicsBody a, PhysicsBody b) → JointConstraint -
override
-
addWheelJoint(
PhysicsBody a, PhysicsBody b, Offset axis) → JointConstraint -
override
-
applyLinearImpulse(
PhysicsBody body, double ix, double iy) → void -
Apply an instantaneous change in momentum to
body.override -
cachePolygonShape(
String cacheId, List< Offset> vertices) → void -
inherited
-
castCircle(
Offset origin, double radius, Offset motion, {Set< PhysicsBody> ? exclude}) → ShapeCastResult? -
Sweep a circle of
radiusfromoriginbymotionand return the first body hit, or null if nothing is in the way.inherited -
castMover(
MoverShape shape, Offset position, Offset translation, {MoverFilter filter = const MoverFilter()}) → double -
How much of
translationa mover ofshapeatpositioncan move before it touches something: 1 for all of it (Box2D's b2World_CastMover). What it starts out touching is ignored, and a one-way platform stops it only when it comes from the solid side and is not partway through it.override -
castRay(
Ray ray, {Set< PhysicsBody> ? exclude}) → RayBodyHit? -
Box2D's query filter cannot express "skip these specific bodies", only
category/mask. So when
excludeis non-empty we have to collect all hits and filter in Dart; otherwise the cheaper closest-hit call is enough. Either way a shape the ray starts inside is passed over.override -
castRayAll(
Ray ray, {Set< PhysicsBody> ? exclude}) → List<RayBodyHit> -
Cast a ray and return all hits sorted nearest-first.
override
-
collideMover(
MoverShape shape, Offset position, {MoverFilter filter = const MoverFilter()}) → List< MoverPlane> -
The surfaces a mover of
shapecentred atpositiontouches, as planes forMoverSolver.solvePlanes(Box2D's b2World_CollideMover, for a capsule or a box). Sensors,MoverFilter.ignoreand bodies the filter leaves out are passed over; a one-way platform counts only from its solid side and only while the mover is not partway through it.override -
createDistanceJoint(
PhysicsBody bodyA, PhysicsBody bodyB, {required double minLength, required double maxLength}) → Box2DJoint? -
createPrismaticJoint(
PhysicsBody bodyA, PhysicsBody bodyB, Offset worldAnchor, Offset axis) → Box2DJoint? -
createRevoluteJoint(
PhysicsBody bodyA, PhysicsBody bodyB, Offset worldAnchor) → Box2DJoint? -
createWeldJoint(
PhysicsBody bodyA, PhysicsBody bodyB, Offset worldAnchor) → Box2DJoint? -
createWheelJoint(
PhysicsBody bodyA, PhysicsBody bodyB, Offset worldAnchor, Offset axis) → Box2DJoint? -
destroyJoint(
Box2DJoint joint) → void - Destroy a Box2D joint and remove it from the engine's joint list.
-
dispose(
) → void -
Clean up physics resources
override
-
getCachedPolygonShape(
String cacheId) → List< Offset> ? -
inherited
-
initialize(
) → void -
Initialize the physics engine
override
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
physicsBodyFromHandle(
int handle) → PhysicsBody? - Resolve a packed body handle (from the impact callback) to a PhysicsBody.
-
pollBodyMoveEvents(
void fn(PhysicsBody body, {required bool fellAsleep})) → void -
Iterate body-move events from the last update.
override
-
pollContactBeginEvents(
void fn(PhysicsBody a, PhysicsBody b, double nx, double ny)) → void -
Iterate all begin-touch contact events from the last update.
override
-
pollContactEndEvents(
void fn(PhysicsBody a, PhysicsBody b)) → void -
Iterate all end-touch (separation) contact events from the last
update.
override
-
pollSensorBeginEvents(
void fn(PhysicsBody a, PhysicsBody b)) → void -
Iterate sensor-begin events (sensor body first touched by visitor).
override
-
pollSensorEndEvents(
void fn(PhysicsBody a, PhysicsBody b)) → void -
Iterate sensor-end events (visitor left the sensor).
override
-
queryAABB(
Rect rect) → List< PhysicsBody> -
Return all active bodies whose bounding box — round all their shapes,
turned with the body — overlaps
rect. The native backend answers with Box2D's boxes, which it keeps a little larger than the shapes (by a tenth of a metre), so a body just outsiderectcan come too.override -
queryCircle(
Offset center, double radius) → List< PhysicsBody> -
Return all active bodies with a shape (turned with its body)
overlapping a circle at
centerwithradius.inherited -
queryPoint(
Offset point) → List< PhysicsBody> -
Return all active bodies containing
point.inherited -
registerImpactCallback(
void callback(int bodyA, int bodyB, double speed), {double speedThreshold = 100.0}) → void -
Register a Dart callback for every contact whose bodies closed faster
than
speedThreshold(units per second) in a step: Box2D's hit events. -
removeBody(
PhysicsBody body) → void -
Remove a physics body, and the joints that hold it. The contacts and
overlaps it was in end without an event, as on the native backend.
override
-
removeJoint(
JointConstraint joint) → void -
Removes
joint; a native one is destroyed, so its bodies come apart.override -
renderDebug(
Canvas canvas, Size size) → void -
Render debug visualization
override
-
setBodyAngularDamping(
PhysicsBody body, double damping) → void -
Set
body's angular damping (spin decay per second).override -
setBodyBullet(
PhysicsBody body, bool isBullet) → void -
Turn continuous collision (PhysicsBody.isBullet) on or off for
body. Only the native backend has it; here it is just the flag.override -
setBodyCanSleep(
PhysicsBody body, bool canSleep) → void -
Allow or forbid
bodyto fall asleep. Forbidding it wakes the body.override -
setBodyDamping(
PhysicsBody body, double damping) → void -
Set
body's linear damping (velocity decay per second).override -
setBodyFilter(
PhysicsBody body, {int? categoryBits, int? maskBits, int? groupIndex}) → void -
Change
body's collision filter at runtime.override -
setBodyFriction(
PhysicsBody body, double friction) → void -
Set
body's surface friction. Swap this to make a platform icy or sticky.override -
setBodyGravityScale(
PhysicsBody body, double scale) → void -
Set the per-body gravity multiplier. See PhysicsBody.gravityScale.
override
-
setBodyOneWay(
PhysicsBody body, bool enabled, {OneWayDirection direction = OneWayDirection.fromAbove}) → void -
Turn
bodyinto a one-way / pass-through platform, solid only when approached fromdirection.override -
setBodyRestitution(
PhysicsBody body, double restitution) → void -
Set
body's bounciness.override -
setBodySensor(
PhysicsBody body, bool isSensor) → void -
Toggle sensor mode on
body.override -
setBodyTransform(
PhysicsBody body, double x, double y, {double? angle}) → void -
Teleport
bodyto (x,y), optionally also settingangle.override -
setBodyType(
PhysicsBody body, BodyType type) → void -
Change how
bodyparticipates in the simulation.override -
setGravity(
double gx, double gy) → void -
Override world gravity at runtime — updates both the Dart gravity vector
and the native Box2D world so they stay in sync.
override
-
toString(
) → String -
A string representation of this object.
inherited
-
update(
double deltaTime) → void -
Advance physics by
deltaTimeseconds.override
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited