Basic Physics Loop
Shows the recommended order for initialization, input, simulation, synchronization, contacts, rendering, and cleanup.
The managed runtime owns a fixed-step accumulator inside jolt_update(). GameMaker continues to run normal events; your controller calls the physics lifecycle functions at deliberate points.
Lifecycle overview#
| GameMaker event | Physics work |
|---|---|
| Create | Call jolt_start(), create layers and persistent bodies. |
| Begin Step / Step before update | Apply input, forces, impulses, and Kinematic targets. |
| Step | Call jolt_update() exactly once for the managed world. |
| Step after update | Read transforms, sync instances, process contacts and raycasts. |
| Draw | Render game assets; optionally call jolt_debug_draw(). |
| Cleanup | Call jolt_stop() from the single world owner. |
Complete controller example#
// CREATE
jolt_start();
floor_body = jolt_box_create_static(0, 0, -0.5, 20, 20, 1);
player_instance = instance_find(obj_player, 0);
player_body = jolt_box_create_dynamic_for_instance(player_instance, 0.8, 0.8, 1.8, {mass: 80});
// STEP: apply input before simulation
if (keyboard_check(vk_right)) {
player_body.add_force(300, 0, 0);
}
var physics_steps = jolt_update();
if (physics_steps >= 0) {
player_body.sync();
var contacts = player_body.get_collisions();
for (var i = 0; i < array_length(contacts); ++i) {
if (contacts[i].type == JOLT_COLLISION_ENTER) {
show_debug_message("Contact began");
}
}
}
// CLEANUP
jolt_stop();Ordering rules#
- Start physics before creating layers, bodies, shapes, constraints, characters, or cloth.
- Apply forces before jolt_update() when they should affect the current frame's simulation.
- Call jolt_update() once per rendered frame from one authoritative controller.
- Read and synchronize transforms after the update.
- Read collision arrays after the update because contact queues are drained at its end.
- Do not step the same managed default world from multiple objects.
- Stop only after gameplay objects no longer need their physics resources.
Variable frame rate#
With no argument, jolt_update() reads GameMaker delta_time in microseconds and feeds a bounded fixed-step accumulator. It may return 0, 1, or several steps. The default fixed timestep is 1/60 second, the frame contribution is capped at 0.25 second, and one update processes at most 8 steps.
Errors#
var steps = jolt_update();
if (steps < 0 || jolt_has_error()) {
var error = jolt_get_error();
show_debug_message(error.context + ": " + error.message);
}High-level operations clear and replace the current managed error state as they run. Handle failure near the operation that can produce it rather than assuming an old error remains indefinitely.
Rendering and interpolation#
Rendering remains separate from simulation. The current high-level runtime retains the fractional accumulator internally but does not expose a public interpolation alpha. Render the latest transform or implement a game-side previous/current transform policy if smooth interpolation is required.