Quick answer: Insert the collider with the rigid body handle as its parent: collider_set.insert_with_parent(collider, body_handle, &mut bodies). A collider inserted without a parent is a static, free collider.
Using the Rapier physics engine, a rigid body falls under gravity but its collider stays at the origin — collisions happen in the wrong place.
Two Insert Paths
collider_set.insert(collider)— a free collider, not attached to any body. It stays where you put it (effectively static).collider_set.insert_with_parent(collider, body_handle, &mut bodies)— attaches the collider to that rigid body. It now moves with the body.
The free-collider path is the bug if you wanted a moving body.
Correct Setup
let body = RigidBodyBuilder::dynamic()
.translation(vector![0.0, 10.0])
.build();
let body_handle = bodies.insert(body);
let collider = ColliderBuilder::cuboid(0.5, 0.5).build();
colliders.insert_with_parent(collider, body_handle, &mut bodies);
Read the Body, Not the Collider
For rendering, read the rigid body’s position each step (bodies[handle].position()). The collider’s world transform is derived from the body plus its local offset — the body is the source of truth.
Local Offset, If Any
A collider can sit offset from its body’s center via its local position. Set that deliberately; an unintended offset looks like “collider not following” when it’s actually following with a shift.
Verifying
The body falls; the collider moves with it; collisions register at the body’s actual position. The rendered mesh, read from the body, lines up with the physics.
“insert vs insert_with_parent. The parent handle is what attaches a collider to a moving body.”
If you use bevy_rapier or another wrapper, the equivalent is making the Collider a child entity of the RigidBody entity — same concept.