GUIDE 04 · PHYSICS

Simulate more
than one genre.

The portable physics contract is the foundation. Characters, vehicles, ragdolls, destructibles, triggers, and user systems are composable consumers of it.

Add the native backend

TerminalSHELL
flutter pub add glint_box3d
physics_setup.dartDART
await GlintBox3dWorld.ensureInitialized();

final physics = GlintBox3dWorld(
  gravity: const Vector3(0, -9.81, 0),
  fixedTimeStep: 1 / 120,
  solverSubSteps: 4,
);

Game code depends on GlintPhysicsWorld, not native Box3D types. The backend supplies angular rigid bodies, sleeping, CCD, contact solving, joints, interpolation, and spatial queries.

Create bodies and colliders

rigid_body.dartDART
final crate = physics.createBody(
  const GlintRigidBodyConfig(
    position: Vector3(0, 3, 0),
    angularDamping: .08,
    ccdEnabled: true,
  ),
);

crate.addCollider(
  const GlintBoxCollider(Vector3(.5, .5, .5)),
  material: const GlintPhysicsMaterial(
    density: 80,
    friction: .75,
    restitution: .05,
  ),
  collisionLayer: 1 << 2,
  collisionMask: 0x7fffffff,
);
Body types

Static world geometry, dynamic solver-controlled bodies, and velocity-driven kinematic bodies.

Collider families

Sphere, box, capsule, cylinder, convex hull, triangle mesh, height field, and compound children.

Motion

Forces, impulses, torque, angular impulse, damping, gravity scale, axis locks, sleep, wake, and CCD.

Filtering

Layers, masks, triggers, body-type inclusion, and exact excluded-body sets on queries.

Step physics at a fixed rate

game_loop.dartDART
GlintGameView(
  models: models,
  onFrame: (elapsed) {
    physics.step(elapsed);
    return GlintGameFrame(
      camera: camera,
      instances: [
        GlintGameInstance(
          model: 'crate',
          transform: crate.toTransform(),
        ),
      ],
    );
  },
)

step accumulates frame time, caps catch-up work, runs fixed callbacks, advances the backend, and exposes an interpolation alpha. stepFixed advances exactly one tick for tests, offline simulation, replay, and rollback.

fixed_system.dartDART
physics.addFixedStepCallback((fixedDt) {
  gameplay.applyQueuedInput(fixedDt);
});

physics.addStepCompletedCallback((stats) {
  profiler.record(stats.backendTime, stats.activeContactCount);
});

Query and retain contact state

The collision stream emits contact begin, fixed-tick stay, contact end, trigger enter, and trigger exit events synchronously with the simulation step. Compound shape pairs are aggregated into stable collider pairs.

contacts.dartDART
physics.collisions.listen((event) {
  switch (event) {
    case GlintContactBegan(:final contacts):
      spawnImpact(contacts);
    case GlintContactStayed(:final duration):
      applyContinuousEffect(duration);
    case GlintTriggerEntered():
      openInteractionPrompt();
    default:
      break;
  }
});

final touchingPlayer = physics.activeContacts
    .where((contact) => contact.involves(player));

Use raycasts, raycast-all, sphere/box overlaps, and sphere/box shape casts for ground tests, cameras, interaction, suspension, explosions, AI perception, and custom gameplay solvers.

Move a general character

The capsule motor uses the public query contract. It handles acceleration, air control, gravity, slopes, sweep-and-slide collision, step climbing, ground snap, moving-platform velocity, jumping, and rollback state.

character.dartDART
final character = GlintCharacterController.create(
  world: physics,
  position: const Vector3(0, 1, 0),
  config: const GlintCharacterControllerConfig(
    height: 1.8,
    radius: .35,
    stepHeight: .3,
    slopeLimitRadians: .78,
  ),
);

character.desiredVelocity = moveDirection * runSpeed;
if (jumpPressed) character.jump(6);

The motor does not own input mapping, camera policy, combat, or animation state. Those remain application systems, making the same controller useful in third-person games, platformers, simulations, and tools.

Compose higher-level systems

Five joint families

Fixed, revolute, prismatic, spherical, and distance constraints with limits, springs, damping, and motors where supported.

Ragdolls

Declarative rig-to-body mapping, kinematic animation drive, dynamic activation, impulses, and partial pose blending.

Raycast vehicles

Suspension, tire grip, anti-roll, dynamic surface reactions, steering, brakes, gears, aero, boost, and telemetry.

Rollback & replay

Body and participant snapshots, fixed-tick input tapes, JSON codecs, quantized state digests, and exact divergence frames.

VEHICLES

GlintRaycastVehicle is one optional consumer of the same world. Nothing in the backend assumes cars, and omitting the vehicle layer removes all vehicle behavior.