Apply Continuous Force to Ammo.js Rigid Body

Applying a continuous directional force to an ammo.js rigid body requires consistently invoking physics force methods within your application’s simulation update loop. This article explains how to use the applyCentralForce method, manage the rigid body’s activation state to prevent the physics engine from putting it to sleep, and implement a performance-friendly update loop for smooth, sustained movement.

1. Choose the Right Force Method

Ammo.js provides two primary methods for applying forces to a btRigidBody:

For a standard directional push, applyCentralForce is the most common choice.

2. Apply Force in the Update Loop

Because forces in physics engines are accumulated and cleared at the end of each physics step, applying a force once behaves like a temporary nudge (an impulse). To make the force continuous, you must apply it on every single frame inside your physics update loop.

Here is how to set up the vector and apply it continuously:

// 1. Create the force vector once (outside the loop to prevent memory leaks)
const forceDirection = new Ammo.btVector3(10.0, 0.0, 0.0); // Force acting along the X-axis

// 2. The main simulation loop
function updatePhysics(deltaTime) {
    // Keep the rigid body active so the engine doesn't put it to "sleep"
    rigidBody.activate(true);

    // Apply the continuous force
    rigidBody.applyCentralForce(forceDirection);

    // Step the physics world
    physicsWorld.stepSimulation(deltaTime, 10);
}

3. Prevent the Rigid Body from Sleeping

Ammo.js automatically deactivates (puts to sleep) rigid bodies that have come to a rest or have very low velocity to optimize performance. Once a body is asleep, applying a force will not automatically wake it up.

To ensure your continuous force is always processed, you must call activate(true) on the rigid body right before applying the force, or change its activation state permanently during initialization:

// Prevent the body from ever sleeping (use with caution for performance)
const DISABLE_DEACTIVATION = 4;
rigidBody.setActivationState(DISABLE_DEACTIVATION);

4. Performance Optimization

Creating new btVector3 objects inside a high-frequency update loop will rapidly trigger garbage collection, causing frame drops. Always instantiate your force vectors once during setup and update their values dynamically if the direction changes:

// Define once during setup
const continuousForce = new Ammo.btVector3(0, 0, 0);

// Update values dynamically when input changes
function updateForceVector(x, y, z) {
    continuousForce.setValue(x, y, z);
}