Physics
The engine integrates Jolt Physics via joltc -- a C API wrapper called from C# via P/Invoke. This provides rigid body dynamics, collision detection, and multiple collider shapes.
Architecture
PhysicsWorld is an engine-layer singleton that survives hot reloads. PhysicsSystem (in game_logic/systems/PhysicsSystem.cs) is hot-reloadable, so you can tune physics parameters live with make dev.
Components
Rigidbody
Defines the dynamics properties of a physics body.
Collider
Defines the shape used for collision detection.
PhysicsSystem
The PhysicsSystem runs three phases each frame:
- Create bodies -- Finds entities with
Rigidbody+Collider+Transformwhere the Jolt body hasn't been created yet. Creates the shape and body in Jolt. - Step physics -- Advances the Jolt simulation using a fixed timestep accumulator (1/60s, max 4 steps per frame).
- Sync transforms -- Reads position and rotation back from Jolt for dynamic bodies and writes them to the ECS
Transformcomponent.
Fixed Timestep
Physics runs at a fixed 1/60s (60 Hz) rate regardless of the rendering frame rate. The PhysicsWorld uses an accumulator pattern:
- Each frame,
DeltaTimeis added to the accumulator - While the accumulator has enough time for a physics step, Jolt is stepped at 1/60s
- Maximum 4 steps per frame to prevent spiral-of-death on frame drops
- If the accumulator exceeds the maximum, it resets to zero
Usage Example
Character-Style Dynamic Controller
For a basic player controller with collisions:
- Use
Rigidbody.MotionType = Dynamic - Use a capsule collider (
ShapeType.Capsule) - Set
LockRotation = trueto prevent tumbling - Drive horizontal velocity from input in
InputMovementSystem - Apply jump by setting positive Y velocity on
Space(with grounded check)
Call PhysicsWorld.Instance.OptimizeBroadPhase() after spawning your initial batch of bodies for better collision detection performance.
Cleanup
Physics bodies are automatically cleaned up:
- Despawning an entity calls
PhysicsWorld.Instance.RemoveBody(entity) - World reset (hot reload) calls
PhysicsWorld.Instance.RemoveAllBodies()before despawning entities - Shutdown calls
PhysicsWorld.Instance.Shutdown()before renderer cleanup
Debug Visualization
Press F3 to toggle the debug overlay, which draws wireframe outlines around all physics colliders. Each collider's wireframe color is configurable via the DebugColor field (defaults to green). This makes it easy to verify collider placement, size, and alignment with visual meshes. See Debug Overlay for details.
Supported shapes: box, sphere, capsule, cylinder. Plane colliders are skipped (too large to render meaningfully).
Precision Note (Interop)
The bundled joltc build uses single precision by default (DOUBLE_PRECISION=OFF), so JPH_RVec3 maps to float on the managed side.
System Registration
Register PhysicsSystem after input/timer systems but before camera and rendering:
FreeCameraSystem can be inserted before CameraFollowSystem when you want debug fly-camera controls.