Step 10
Building the Simulation Subsystem
A practical architecture for time, forces, bodies, worlds, integrators, and system orchestration
Executive Sumary

This article presents a compact simulation architecture for btm-framework, centered on fixed timestep control, modular rigid bodies, force accumulation, world management, and interchangeable integrators. The design keeps simulation predictable and extensible while providing a practical foundation for physics, animation, particles, camera motion, AI steering, and future real-time engine systems.

Introduction

Simulation is the core runtime loop behind responsive, time-driven behavior. This article builds a complete , simulation subsystem for btm-framework, showing how the major pieces fit together:

  • Time & fixed timestep
  • Forces & acceleration
  • Bodies & state
  • World management
  • Euler & RK4 integration
  • A unified simulation_system that ties everything together

The result is a clean foundation for physics, animation, particles, camera motion, AI steering, and any feature that depends on consistent simulation updates.

System Overview

The simulation subsystem is organized around a small set of responsibilities: time control, world management, force . application, state integration, and output for rendering.

┌───────────────────────────────┐
│      simulation_system        │
│  - manages timestep           │
│  - runs integrator            │
│  - updates world              │
└──────────────┬────────────────┘
               │
      ┌────────┴─────────┐
      │ simulation_world │
      │ - bodies         │
      │ - global forces  │
      └────────┬─────────┘
               │
    ┌──────────┴───────────┐
    │   rigid_body         │
    │ - state              │
    │ - mass               │
    │ - accumulated Forces │
    └──────────┬───────────┘
               │
      ┌────────┴─────────┐
      │ simulation_state │
      │ pos, vel, acc    │
      └──────────────────┘

The simulation_system coordinates the update loop. Each cycle progresses through a consistent sequence:

  1. Measure frame time / accumulate fixed timestep
  2. Apply forces
  3. Compute accelerations
  4. Integrate states
  5. Produce updated positions for rendering

This pattern keeps simulation state stable while allowing rendering to run at its own pace.

Time & Fixed Timestep

Real time is continuous; simulation time is discrete. A fixed timestep converts variable frame timing into predictable simulation steps.

A fixed timestep accumulator preserves stability and determinism even when rendering performance fluctuates.

frameTime → accumulator → simulate(dt) → render

Here is the accumulator in action:

accumulator = 0
while (true) {
    frameTime = getFrameTime()
    accumulator += frameTime
    while (accumulator >= dt) {
        simulate(dt)
        accumulator -= dt
    }
    render()
}

With this approach, physics can advance at a fixed rate, such as 60 Hz, while rendering remains independent. For off-screen calculations, there is no need to wait for real time to pass: the system can simply advance to the next timestep as quickly as needed. This is how simulation solvers typically operate.

Bodies & State

Each simulated object is represented by a rigid_body. It stores the minimum information required to advance

  • Position
  • Velocity
  • Acceleration
  • Mass
  • Accumulated forces
rigid_body
├── simulation_state
│    ├── position
│    ├── velocity
│    └── acceleration
└── m_mass
└── m_accumulatedForce

Keeping the body small makes the simulation easier to reason about, test, and extend.

Forces & Acceleration

During each step, the world gathers all active forces before computing acceleration:

f_total = f_gravity + f_drag + f_spring + ...

Acceleration then follows directly from Newton’s second law:

a = f_total / m_mass

In a typical simulation pipeline, the flow can be summarized as follows:

ForcesAccumulateCompute Acceleration

Separating force accumulation from acceleration keeps the design extensible. New force generators—such as wind, constraints, springs, or impulses—can be added without changing the integration pipeline.

Integration: Euler & RK4

Integration advances each body from its current state to the next timestep. This tutorial compares two common approaches.

Euler: simple and fast
v += a * dt;
x += v * dt;

The same Euler step can also be written in equation form:

x(t+dt) = x(t) + v(t)*dt
v(t+dt) = v(t) + a(t)*dt
RK4: more accurate and stable

RK4 improves stability by sampling the derivative four times within a single timestep:

k1 = f(state);
k2 = f(state + k1*dt/2);
k3 = f(state + k2*dt/2);
k4 = f(state + k3*dt);

state += (k1 + 2k2 + 2k3 + k4) * dt/6;

Visually, those four samples trace the timestep from the initial state through two midpoint estimates and a final endpoint estimate:

k1midpointk2midpointendpointk4

By combining multiple derivative samples, RK4 typically produces smoother and more accurate motion than Euler, particularly when acceleration changes quickly.

simulation_world

The simulation_world owns the simulation scene. It manages:

  • All bodies
  • Global forces (gravity)
  • Force accumulation
  • Acceleration computation
simulation_world
 ├── m_bodies[]
 ├── Gravity via m_forces
 ├── accumulateForces()
 └── computeAccelerations()

In practice, the world prepares every body for integration by applying shared forces and computing the accelerations required for the next step.

simulation_system

The simulation_system orchestrates the subsystem by connecting time management, the simulation world, and the selected integrator.

Simulation_system
 ├── keeps track of time (fixed or variable)
 ├── simulation_world
 ├── integrator (Euler or RK4)
 └── step_simulation

A typical step follows this order:

frameTime = determine the elapsed time, fixed time step or dynamic time step

// reset forces and accelerations
world.clearForces()
world.accumulateForces()
world.computeAccelerations()

// integrate over time to find the next state
For every body in the world:
    integrator.integrate(body.state, frameTime)

The structure is intentionally conventional: clear forces, apply forces, compute acceleration, and integrate each body forward.

Complete Pipeline

Assembled end to end, the subsystem forms a simple pipeline:

┌──────────────────────────────────────────────┐
│              simulation_system               │
│                                              │
│  frameTime = clock.frameDeltaTime()          │
│  simulate(frameTime)                         │
└───────────────────────┬──────────────────────┘
                        │
                   simulate(dt)
                        │
    ┌───────────────────┴───────────────────┐
    │            simulation_world           │
    │  clearForces()                        │
    │  accumulateForces()                   │
    │  computeAccelerations()               │
    └───────────────────┬───────────────────┘
                        │
                  integrate(dt)
                        │
    ┌───────────────────┴───────────────────┐
    │              Integrator               │
    │  Euler or RK4                         │
    └───────────────────┬───────────────────┘
                        │
                  update state
                        │
    ┌───────────────────┴───────────────────┐
    │              rigid_body               │
    │  position, velocity, acceleration     │
    └───────────────────────────────────────┘

This pipeline can support a broad range of engine features:

  • Physics
  • Animation
  • Particle systems
  • Camera motion
  • AI steering
  • Any time based behavior
Why This Architecture Matters

This architecture matters because it shows how the main parts of a simulation engine fit together:

  • Organizing simulation the way real engines do
  • Using a fixed timestep to keep updates predictable
  • Connecting forces, mass, and acceleration
  • Comparing integrators and their trade-offs
  • Building simulation code that is modular and reusable
  • Keeping world, body, and system responsibilities separate

Together, these ideas provide the foundation for the next stages of the BeforeTheMesh simulation arc.

Conclusion

A well-designed simulation subsystem separates time management, force calculation, world state, and integration into clear responsibilities. That separation keeps the engine predictable, testable, and extensible as new behaviors are added. With fixed timestep control, modular bodies, a dedicated world, and interchangeable integrators, the framework now has a stable base for more advanced systems such as collision detection, constraints, and real-time visualization.

Next Steps

Future work can expand this foundation to include:

  • Collision detection
  • Spatial partitioning
  • Constraints and joints
  • Impulse-based responses
  • Rigid-body rotation
  • Real-time visualization
  • Profiling and instrumentation