rigid_body_forces_and_impulses
In addition to gravity, it is possible to add custom forces (or torques) or apply impulses (or torque impulses) to dynamic rigid-bodies in order to make them move in specific ways. Forces affect the rigid-body's acceleration whereas impulses affect the rigid-body's velocity. They are both based on the familiar equations:
- Forces: the acceleration change is equal to the force divided by the mass:
- Impulses: the velocity change is equal to the impulse divided by the mass:
Forces can be added, and impulses can be applied, to a rigid-body
- Example 2D
- Example 3D
let rigid_body = &mut world.bodies[rigid_body_handle];
// The `true` argument makes sure the rigid-body is awake.
rigid_body.reset_forces(true); // Reset the forces to zero.
rigid_body.reset_torques(true); // Reset the torques to zero.
rigid_body.add_force(Vector::new(0.0, 1000.0), true);
rigid_body.add_torque(100.0, true);
rigid_body.add_force_at_point(Vector::new(0.0, 1000.0), Vector::new(1.0, 2.0), true);
rigid_body.apply_impulse(Vector::new(0.0, 1000.0), true);
rigid_body.apply_torque_impulse(100.0, true);
rigid_body.apply_impulse_at_point(Vector::new(0.0, 1000.0), Vector::new(1.0, 2.0), true);
let rigid_body = &mut world.bodies[rigid_body_handle];
// The `true` argument makes sure the rigid-body is awake.
rigid_body.reset_forces(true); // Reset the forces to zero.
rigid_body.reset_torques(true); // Reset the torques to zero.
rigid_body.add_force(Vector::new(0.0, 1000.0, 0.0), true);
rigid_body.add_torque(Vector::new(100.0, 0.0, 0.0), true);
rigid_body.add_force_at_point(
Vector::new(0.0, 1000.0, 0.0),
Vector::new(1.0, 2.0, 3.0),
true,
);
rigid_body.apply_impulse(Vector::new(0.0, 1000.0, 0.0), true);
rigid_body.apply_torque_impulse(Vector::new(100.0, 0.0, 0.0), true);
rigid_body.apply_impulse_at_point(
Vector::new(0.0, 1000.0, 0.0),
Vector::new(1.0, 2.0, 3.0),
true,
);
- Example 2D
- Example 3D
commands
.spawn(RigidBody::Dynamic)
.insert(ExternalForce {
force: Vec2::new(1000.0, 2000.0),
torque: 140.0,
})
.insert(ExternalImpulse {
impulse: Vec2::new(100.0, 200.0),
torque_impulse: 14.0,
})
// Needed to read the world-space center-of-mass from `apply_impulse_at_point`.
.insert(ReadWorldMassProperties::default());
/* Apply forces and impulses inside of a system. */
fn apply_forces(
mut ext_forces: Query<&mut ExternalForce>,
mut ext_impulses: Query<&mut ExternalImpulse>,
) {
// Apply forces.
for mut ext_force in ext_forces.iter_mut() {
ext_force.force = Vec2::new(1000.0, 2000.0);
ext_force.torque = 0.4;
}
// Apply impulses.
for mut ext_impulse in ext_impulses.iter_mut() {
ext_impulse.impulse = Vec2::new(100.0, 200.0);
ext_impulse.torque_impulse = 0.4;
}
}
/* Apply an impulse at a world-space point inside of a system. */
fn apply_impulse_at_point(mut bodies: Query<(&mut ExternalImpulse, &ReadWorldMassProperties)>) {
for (mut ext_impulse, mprops) in bodies.iter_mut() {
// The torque impulse is deduced from the world-space center-of-mass of the rigid-body.
*ext_impulse += ExternalImpulse::at_point(
Vec2::new(0.0, 100.0),
Vec2::new(1.0, 2.0),
mprops.center_of_mass,
);
}
}
/* Apply forces when the rigid-body is created. */
commands
.spawn(RigidBody::Dynamic)
.insert(ExternalForce {
force: Vec3::new(10.0, 20.0, 30.0),
torque: Vec3::new(1.0, 2.0, 3.0),
})
.insert(ExternalImpulse {
impulse: Vec3::new(1.0, 2.0, 3.0),
torque_impulse: Vec3::new(0.1, 0.2, 0.3),
})
// Needed to read the world-space center-of-mass from `apply_impulse_at_point`.
.insert(ReadWorldMassProperties::default());
/* Apply forces and impulses inside of a system. */
fn apply_forces(
mut ext_forces: Query<&mut ExternalForce>,
mut ext_impulses: Query<&mut ExternalImpulse>,
) {
// Apply forces.
for mut ext_force in ext_forces.iter_mut() {
ext_force.force = Vec3::new(1000.0, 2000.0, 3000.0);
ext_force.torque = Vec3::new(0.4, 0.5, 0.6);
}
// Apply impulses.
for mut ext_impulse in ext_impulses.iter_mut() {
ext_impulse.impulse = Vec3::new(100.0, 200.0, 300.0);
ext_impulse.torque_impulse = Vec3::new(0.4, 0.5, 0.6);
}
}
/* Apply an impulse at a world-space point inside of a system. */
fn apply_impulse_at_point(mut bodies: Query<(&mut ExternalImpulse, &ReadWorldMassProperties)>) {
for (mut ext_impulse, mprops) in bodies.iter_mut() {
// The torque impulse is deduced from the world-space center-of-mass of the rigid-body.
*ext_impulse += ExternalImpulse::at_point(
Vec3::new(0.0, 100.0, 0.0),
Vec3::new(1.0, 2.0, 3.0),
mprops.center_of_mass,
);
}
}
The ExternalForce component is applied at each timestep until it is modified or removed, whereas the
ExternalImpulse component is applied only once and then automatically reset to zero. A force or impulse applied
at a specific world-space point can be built with ExternalForce::at_point or ExternalImpulse::at_point: these
take the world-space center-of-mass of the rigid-body, which can be read, e.g., from its ReadWorldMassProperties
component.
- Example 2D
- Example 3D
// The `true` argument makes sure the rigid-body is awake.
rigidBody.resetForces(true); // Reset the forces to zero.
rigidBody.resetTorques(true); // Reset the torques to zero.
rigidBody.addForce({ x: 0.0, y: 1000.0 }, true);
rigidBody.addTorque(100.0, true);
rigidBody.addForceAtPoint({ x: 0.0, y: 1000.0 }, { x: 1.0, y: 2.0 }, true);
rigidBody.applyImpulse({ x: 0.0, y: 1000.0 }, true);
rigidBody.applyTorqueImpulse(100.0, true);
rigidBody.applyImpulseAtPoint({ x: 0.0, y: 1000.0 }, { x: 1.0, y: 2.0 }, true);
// The `true` argument makes sure the rigid-body is awake.
rigidBody.resetForces(true); // Reset the forces to zero.
rigidBody.resetTorques(true); // Reset the torques to zero.
rigidBody.addForce({ x: 0.0, y: 1000.0, z: 0.0 }, true);
rigidBody.addTorque({ x: 100.0, y: 0.0, z: 0.0 }, true);
rigidBody.addForceAtPoint({ x: 0.0, y: 1000.0, z: 0.0 }, { x: 1.0, y: 2.0, z: 3.0 }, true);
rigidBody.applyImpulse({ x: 0.0, y: 1000.0, z: 0.0 }, true);
rigidBody.applyTorqueImpulse({ x: 100.0, y: 0.0, z: 0.0 }, true);
rigidBody.applyImpulseAtPoint({ x: 0.0, y: 1000.0, z: 0.0 }, { x: 1.0, y: 2.0, z: 3.0 }, true);
- Example 2D
- Example 3D
// The last `1` argument makes sure the rigid-body is awake.
r2RigidBody_ResetForces(rigid_body_handle, 1); // Reset the forces to zero.
r2RigidBody_ResetTorques(rigid_body_handle, 1); // Reset the torques to zero.
r2RigidBody_AddForce(rigid_body_handle, r2Vector(0.0, 1000.0), 1);
r2RigidBody_AddTorque(rigid_body_handle, 100.0, 1);
r2RigidBody_AddForceAtPoint(rigid_body_handle, r2Vector(0.0, 1000.0), r2Vector(1.0, 2.0), 1);
r2RigidBody_ApplyImpulse(rigid_body_handle, r2Vector(0.0, 1000.0), 1);
r2RigidBody_ApplyTorqueImpulse(rigid_body_handle, 100.0, 1);
r2RigidBody_ApplyImpulseAtPoint(rigid_body_handle, r2Vector(0.0, 1000.0), r2Vector(1.0, 2.0), 1);
// The last `1` argument makes sure the rigid-body is awake.
r3RigidBody_ResetForces(rigid_body_handle, 1); // Reset the forces to zero.
r3RigidBody_ResetTorques(rigid_body_handle, 1); // Reset the torques to zero.
r3RigidBody_AddForce(rigid_body_handle, r3Vector(0.0, 1000.0, 0.0), 1);
r3RigidBody_AddTorque(rigid_body_handle, r3Vector(100.0, 0.0, 0.0), 1);
r3RigidBody_AddForceAtPoint(rigid_body_handle, r3Vector(0.0, 1000.0, 0.0), r3Vector(1.0, 2.0, 3.0), 1);
r3RigidBody_ApplyImpulse(rigid_body_handle, r3Vector(0.0, 1000.0, 0.0), 1);
r3RigidBody_ApplyTorqueImpulse(rigid_body_handle, r3Vector(100.0, 0.0, 0.0), 1);
r3RigidBody_ApplyImpulseAtPoint(rigid_body_handle, r3Vector(0.0, 1000.0, 0.0), r3Vector(1.0, 2.0, 3.0), 1);
The forces and torques added with r3RigidBody_AddForce, r3RigidBody_AddTorque, and r3RigidBody_AddForceAtPoint
are accumulated until they are reset with r3RigidBody_ResetForces and r3RigidBody_ResetTorques. Their current sum
can be read with r3RigidBody_UserForce and r3RigidBody_UserTorque. The impulses, on the other hand, modify the
velocity of the rigid-body immediately. The points given to r3RigidBody_AddForceAtPoint and
r3RigidBody_ApplyImpulseAtPoint are expressed in world-space.
rigid_body = world.rigid_bodies[rigid_body_handle]
# The rigid-body is woken up, unless `wake_up=False` is given.
rigid_body.reset_forces() # Reset the forces to zero.
rigid_body.reset_torques() # Reset the torques to zero.
rigid_body.add_force((0.0, 1000.0, 0.0))
rigid_body.add_torque((100.0, 0.0, 0.0))
rigid_body.add_force_at_point((0.0, 1000.0, 0.0), (1.0, 2.0, 3.0))
rigid_body.apply_impulse((0.0, 1000.0, 0.0))
rigid_body.apply_torque_impulse((100.0, 0.0, 0.0))
rigid_body.apply_impulse_at_point((0.0, 1000.0, 0.0), (1.0, 2.0, 3.0))
The forces and torques added with RigidBody.add_force, RigidBody.add_torque, and RigidBody.add_force_at_point
are accumulated until they are reset with RigidBody.reset_forces and RigidBody.reset_torques. Their current sum is
given by the RigidBody.user_force and RigidBody.user_torque properties. The impulses, on the other hand, modify the
velocity of the rigid-body immediately. The points given to add_force_at_point and apply_impulse_at_point are
expressed in world-space.
Keep in mind that a dynamic rigid-body with a zero mass won't be affected by a linear force/impulse, and a rigid-body with a zero angular inertia won't be affected by torques/torque impulses. So if your force doesn't appear to do anything, make sure that:
- The rigid-body is dynamic.
- It is strong enough to make the rigid-body move (try a very large value and see if it does something).
- The rigid-body has a non-zero mass or angular inertia either because they were set explicitly, or because they were computed automatically from colliders with non-zero densities.
wake_up parameter to true).r3RigidBody_WakeUp or setting the last wake_up argument to 1).RigidBody.wake_up or keeping the wake_up argument to its default value True).