One pass over the contacts is not enough when contacts push against each other, so the solver runs several passes per step. Today you resolve the whole contact list, iterated.
Resolve every contact in the world a fixed number of iterations per step so coupled contacts converge.
A single body against the floor resolves in one pass, but a stack does not: pushing
the bottom box out of the floor shoves it into the box above, whose contact you already
solved, so one sweep leaves the stack slightly wrong. The fix is to iterate - sweep
the whole contact list several times per step, each pass nudging every contact a little
closer to consistent. This is the sequential impulse solver at the heart of Box2D,
and a handful of iterations (here 8) is enough for believable stacks.
Collect all the frame’s contacts once, then loop the velocity resolve over that list
VelocityIterations times before doing a single positional correction per contact. Two
independent contacts, like the two far-apart stacks here, each resolve in the first
iteration and the rest are harmless - a contact already at rest gets an impulse of zero,
so extra passes never overshoot. Coupled contacts are where the extra passes earn their
keep, which the settling capstone shows directly. The number of iterations trades cost
for stability.
// World gains a VelocityIterations field. In Step, after collecting contacts:// for iter := 0; iter < w.VelocityIterations; iter++ {// for _, c := range contacts { Resolve(c.a, c.b, c.manifold) }// }// then correct positions once per contact