Reset Ammo.js Physics World Without Reloading
Resetting an Ammo.js physics simulation back to its original state is a common requirement for games and interactive 3D applications, allowing players to restart levels instantly without reloading the entire webpage. This article outlines the two most effective methods to completely reset an Ammo.js physics world: recreating the physics world from scratch to clear all cached data, or manually resetting individual rigid bodies to their initial positions and velocities.
Method 1: Recreating the Physics World (Recommended)
The most reliable way to reset Ammo.js is to destroy the existing physics world and instantiate a new one. Ammo.js (a port of the Bullet physics engine) caches collision algorithms, contact points, and broadphase proxies. Simply moving objects can sometimes leave ghost collisions or cached forces behind. Recreating the world guarantees a clean slate.
Step 1: Clean Up Existing Resources
To prevent memory leaks in WebAssembly/C++, you must explicitly
destroy all rigid bodies, constraints, and the physics world components
using Ammo.destroy().
function cleanupPhysics() {
// 1. Remove and destroy constraints
for (let i = constraints.length - 1; i >= 0; i--) {
const constraint = constraints[i];
physicsWorld.removeConstraint(constraint);
Ammo.destroy(constraint);
}
constraints = [];
// 2. Remove and destroy rigid bodies
for (let i = rigidBodies.length - 1; i >= 0; i--) {
const body = rigidBodies[i];
physicsWorld.removeRigidBody(body);
if (body.getMotionState()) {
Ammo.destroy(body.getMotionState());
}
Ammo.destroy(body);
}
rigidBodies = [];
// 3. Destroy the core world infrastructure
Ammo.destroy(physicsWorld);
Ammo.destroy(solver);
Ammo.destroy(overlappingPairCache);
Ammo.destroy(dispatcher);
Ammo.destroy(collisionConfiguration);
}Step 2: Re-initialize the Physics World
After cleanup, call your initialization function to rebuild the physics world and re-populate it with your starting scene objects.
function initPhysics() {
collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
overlappingPairCache = new Ammo.btDbvtBroadphase();
solver = new Ammo.btSequentialImpulseConstraintSolver();
physicsWorld = new Ammo.btDiscreteDynamicsWorld(
dispatcher,
overlappingPairCache,
solver,
collisionConfiguration
);
// Reset gravity
physicsWorld.setGravity(new Ammo.btVector3(0, -9.81, 0));
// Recreate your ground, boundaries, and interactive objects here
createSceneObjects();
}
function resetSimulation() {
cleanupPhysics();
initPhysics();
}Method 2: Manually Resetting Rigid Bodies
If your scene is highly complex and recreating the world causes a noticeable performance stutter, you can manually reset the transform, velocity, and forces of each active rigid body.
To make this work, you must store the initial position, rotation, and mass of every object when it is first created.
Step 1: Clear Forces and Velocities
Simply moving a rigid body is not enough; you must clear its momentum so it does not continue moving with its pre-reset velocity.
function resetRigidBody(body, initialPosition, initialRotation) {
// 1. Clear forces and velocities
const zeroVector = new Ammo.btVector3(0, 0, 0);
body.setLinearVelocity(zeroVector);
body.setAngularVelocity(zeroVector);
body.clearForces();
// 2. Define the initial transform
const transform = new Ammo.btTransform();
transform.setIdentity();
const origin = new Ammo.btVector3(initialPosition.x, initialPosition.y, initialPosition.z);
transform.setOrigin(origin);
const rotation = new Ammo.btQuaternion(
initialRotation.x,
initialRotation.y,
initialRotation.z,
initialRotation.w
);
transform.setRotation(rotation);
// 3. Apply transform to motion state and world transform
body.setWorldTransform(transform);
if (body.getMotionState()) {
body.getMotionState().setWorldTransform(transform);
}
// 4. Force Ammo.js to update the collision bounds
physicsWorld.updateSingleAabb(body);
// 5. Activate the body (wakes it up if it went to sleep)
body.activate(true);
// Clean up temporary Ammo objects to prevent memory leaks
Ammo.destroy(zeroVector);
Ammo.destroy(origin);
Ammo.destroy(rotation);
Ammo.destroy(transform);
}Step 2: Reset the Entire Loop
Iterate through your tracking array and apply the reset function to each object:
function resetAllBodies() {
for (let i = 0; i < rigidBodies.length; i++) {
const body = rigidBodies[i];
const initialState = initialStates[i]; // Object containing saved pos/rot data
resetRigidBody(body, initialState.position, initialState.rotation);
}
}Using Method 1 is highly recommended for standard games to guarantee that collision registers, solver constraints, and contact manifolds are entirely wiped out, preventing physics bugs upon restart. Use Method 2 only if real-time constraints require a sub-millisecond reset loop.