Real objects spin, not just translate. Add rotation to the simulation with angular velocity, torque, and the moment of inertia — the rotational counterparts of velocity, force, and mass.
A rigid body has two kinds of motion: linear (its center of mass translating) and angular (spinning about that center). Each linear concept has a rotational twin — velocity/angular velocity, force/torque, mass/moment of inertia. Simulating rotation means integrating angular velocity into orientation the same way you integrate velocity into position.
Every linear quantity has a rotational counterpart:
LINEAR ANGULAR
position orientation (angle / quaternion)
velocity angular velocity (spin rate)
force torque (rotational force)
mass moment of inertia (resistance to spin)
F = m * a torque = I * angular_acceleration
A rigid body integrates BOTH: velocity -> position, and angular velocity ->
orientation. Add the angular half and objects tumble and roll realistically.A force applied off-center produces torque, which spins the body. Torque equals the lever arm (from the center of mass to the contact point) crossed with the force. Dividing torque by the moment of inertia gives angular acceleration, which you integrate into angular velocity and then orientation — exactly mirroring the linear F = ma pipeline.
def cross2(a, b): return a[0]*b[1] - a[1]*b[0] # 2D cross -> scalar torque
class RigidBody:
def __init__(self, mass, inertia):
self.mass, self.inertia = mass, inertia
self.angle = 0.0
self.angular_vel = 0.0
def apply_force_at(self, force, point, center):
r = (point[0]-center[0], point[1]-center[1]) # lever arm
torque = cross2(r, force) # off-center force -> spin
return torque
def step(self, torque, dt):
angular_acc = torque / self.inertia # torque = I * alpha
self.angular_vel += angular_acc * dt
self.angle += self.angular_vel * dt # integrate into orientation
# a force through the center = no spin; off-center = torque = rotation.The moment of inertia is rotational mass: how hard it is to change a body’s spin, depending on both its mass and how that mass is distributed. Mass far from the center resists spinning more (a figure skater pulling their arms in speeds up). Each shape has an inertia formula; the physics engine computes it from the collider so torque produces realistic angular acceleration.
Moment of inertia (I) = "rotational mass" — resistance to changing spin.
Depends on mass AND how far it's spread from the center.
solid disk (radius r): I = 1/2 * m * r²
solid box (w x h): I = 1/12 * m * (w² + h²)
point mass at distance d: I = m * d²
Mass far from the center resists spin MORE (skater pulls arms in -> smaller I
-> spins faster, conserving angular momentum). The engine computes I from the
collider shape so 'torque = I * angular_acc' gives realistic rotation.Rotation makes collision response richer: an impulse applied at a contact point away from the center imparts spin as well as a velocity change, so a box hit at a corner tumbles. Full rigid-body solvers include the rotational terms in the impulse calculation. You rely on the engine for the exact math, but understanding that off-center hits cause rotation explains why objects tumble and topple realistically.
Why boxes tumble when hit at a corner:
an impulse at a CONTACT POINT away from the center of mass changes BOTH:
- linear velocity (the body moves)
- angular velocity (the body SPINS), by torque = r x impulse
So the full impulse formula includes the rotational terms (the lever arm at
each contact). A hit through the center -> pure slide; a hit at an edge/corner
-> the object rotates + topples.
Engines (Box2D, Bullet, PhysX) solve this coupled linear+angular system for you;
knowing it explains the realistic tumbling you see.