To move things around, you'll need to apply forces or impulses to a body. Forces act gradually over time to change the velocity of a body while impulses can change a body's velocity immediately. As an example, imagine you have a broken down car and you want to move it. You could use a force by slowly driving another car up next to it until their bumpers touched and then push it, causing it to accelerate over time. Or you could use an impulse by driving the other car into it at full speed. Both methods have their place depending on what you are trying to simulate.
You can also 'warp' a body instantaneously by simply setting its location. This can be handy for games where you need a teleport feature, but bear in mind that this is not realistic physics! The whole point of a physics simulator like Box2D is to make things look real, and to this end I would recommend using forces and impulses to move bodies as much as you can. Sometimes it might seem tricky to think of a way to do this, but in the real world everything happens via forces or impulses, so unless you are creating a feature which is obviously not real-world (teleport etc), keep thinking. It may end up giving you less problems down the line.
Angular movement can also be controlled by forces and impulses, with the same gradual/immediate characteristics as their linear versions. Angular force is called torque. Think of this as a twisting strength, like when you twist the cap off a bottle - the bottle doesn't go anywhere, but you are still applying a force (torque) to it.
In this topic, we'll make three bodies and try using each one of the above-mentioned methods to move and twist them. Let's set up a scene similar to the one in the shapes topic, but with the shapes all the same type.
// Array to keep track of three body Ids
let bodyIds = new Array(3);
// Create the world
const worldDef = b2DefaultWorldDef();
const worldId = b2CreateWorld(worldDef);
// Body definition
const bodyDef = b2DefaultBodyDef();
bodyDef.type = DYNAMIC;
// Shape definition
const vertices = [
new b2Vec2(-1, -1),
new b2Vec2(1, -1),
new b2Vec2(1, 1),
new b2Vec2(-1, 1)
];
const hull = b2ComputeHull(vertices, vertices.length);
const polygonShape = b2MakePolygon(hull, 0);
// Fixture definition
const shapeDef = b2DefaultShapeDef();
shapeDef.density = 1;
// Create identical bodies in different positions
for (let i = 0; i < 3; i++) {
bodyDef.position = new b2Vec2(-10 + i * 10, 20);
const bodyId = b2CreateBody(worldId, bodyDef);
bodyIds[i] = bodyId;
b2CreatePolygonShape(bodyId, shapeDef, polygonShape);
}
// Create a static floor
bodyDef.type = STATIC;
bodyDef.position = new b2Vec2(0, 0);
const floorId = b2CreateBody(worldId, bodyDef);
const segment = new b2Segment();
segment.point1 = new b2Vec2(-15, 0);
segment.point2 = new b2Vec2(15, 0);
b2CreateSegmentShape(floorId, shapeDef, segment);
Linear Movement
There are three main ways to affect a body's linear motion:
- Gradual force (accumulates over time)
- Immediate impulse (instant change in velocity)
- Direct position changes
Let's implement keyboard controls to test these different methods:
// Track key states
const keys = {
ArrowUp: false,
ArrowDown: false,
ArrowLeft: false,
ArrowRight: false
};
// Track one-shot actions
const oneShot = {
ArrowUp: false,
ArrowLeft: false
};
// Set up key listeners
window.addEventListener('keydown', (event) => {
if (keys.hasOwnProperty(event.code)) {
keys[event.code] = true;
}
});
window.addEventListener('keyup', (event) => {
if (keys.hasOwnProperty(event.code)) {
keys[event.code] = false;
// Reset one-shot flags when key is released
if (oneShot.hasOwnProperty(event.code)) {
oneShot[event.code] = false;
}
}
});
function handleForces(world) {
// Example bodies (ensure these exist in your world)
const gradualBody = bodyIds[0]; // Force demo
const impulseBody = bodyIds[1]; // Impulse demo
const warpBody = bodyIds[2]; // Position demo
// 1. Gradual Force: Continuous upward force while Up is held
if (keys.ArrowUp) {
b2Body_ApplyForceToCenter(
gradualBody,
new b2Vec2(0, 50),
true
);
}
// 2. Impulse: One-time push when Left is first pressed
if (keys.ArrowLeft && !oneShot.ArrowLeft) {
b2Body_ApplyLinearImpulseToCenter(
impulseBody,
new b2Vec2(0, 50),
true
);
oneShot.ArrowLeft = true;
}
// 3. Position Change: Teleport when Right is pressed
if (keys.ArrowRight) {
b2Body_SetTransform(
warpBody,
new b2Vec2(10, 20),
b2Body_GetAngle(warpBody)
);
}
}
// Inside update function
function update() {
handleForces(world);
b2World_Step(worldId, fixedTimeStep, subStepCount);
}
Note: If you're using Phaser, replace the key listeners with Phaser's input system:
const keys = this.input.keyboard.createCursorKeys(); // Then use keys.up.isDown, etc.
Force Application Points
Forces and impulses can be applied at different points on a body:
// Apply at center of mass (most common)
b2Body_ApplyForceToCenter(
bodyId,
force,
true
);
// Apply at specific point (e.g., corner)
const localPoint = new b2Vec2(1, 1); // Local coordinates
const worldPoint = b2Body_GetWorldPoint(bodyId, localPoint);
b2Body_ApplyForce(
bodyId,
force,
worldPoint,
true
);
Angular Movement
Similar to linear movement, we can affect rotation in different ways:
function handleRotation(world) {
const gradualBody = bodyIds[0];
const impulseBody = bodyIds[1];
// Gradual rotation: continuous torque
if (keys.ArrowLeft) {
b2Body_ApplyTorque(gradualBody, 20, true);
}
// Immediate rotation: angular impulse
if (keys.ArrowRight && !oneShot.ArrowRight) {
b2Body_ApplyAngularImpulse(impulseBody, 20, true);
oneShot.ArrowRight = true;
}
}
With gravity on, you'll see that even though we are only trying to 'twist' these boxes they still move around a bit, but that's only because they collide with the ground and act like square wheels. For a better illustration of what torque and angular impulse are doing, turn gravity off. In a zero-gravity scene, now we can see why only one parameter is necessary for angular force/impulse functions - since no linear movement is caused, the only thing we need to specify is which way the rotation should be. Unlike linear forces above there is never any offset possible because the rotation is always about the body's center of mass.
Given the same magnitude parameter, ApplyTorque will take one second to gain as much rotational velocity as ApplyAngularImpulse does immediately.
Key Differences
-
Force vs Impulse
- Forces accumulate over time, creating smooth acceleration
- Impulses cause immediate velocity changes
- Position changes bypass physics entirely
-
Linear vs Angular
- Linear forces/impulses are vectors and affect position and linear velocity
- Torque/angular impulses are scalar and affect rotation and angular velocity
-
Application Points
- Linear forces can be applied at any point, there are convenience functions to apply it at the center
- Angular forces always rotate around the center of mass
Credits
This tutorial is adapted from an original piece of work created by Chris Campbell and is used under license.