Pinball Bumper Physics Audit
Watch three collision resolvers on one table: the correct one never creates energy, and the two classic bugs fail in completely different ways.
The same table, three resolvers. The correct one settles down; the kick converges on one speed and stays there; the un-normalised normal throws the ball through the wall on the first contact. Walls are always resolved correctly, so only the bumpers differ. Nothing is uploaded.
The formula cannot create energy
The right resolver is v′ = v − (1 + e)(v · n) n with n a unit vector: it reflects the part of the velocity heading into the bumper and leaves the sideways part alone. Sweeping every restitution from 0 to 1, every contact angle, every approach angle and ten speeds — 4,528,251 approaching contacts — the energy went up 0 times.
The worst ratio seen is exactly 1, and that case is a perfectly elastic head-on hit, which is supposed to conserve energy. Every restitution below 1 strictly loses. So a browser pinball table that gains energy is not suffering from this formula — it is suffering from something done around it.
Two details the tests pin separately: the sideways component comes out untouched, which is what makes a glancing hit glance rather than stop; and a contact the ball is already moving away from is left completely alone, which is what stops a ball buzzing inside a bumper.
Mistake one: the normal left un-normalised
The vector from the bumper's centre to the ball gives the normal's direction. It is not the normal — it has length R. Drop it into the formula unchanged and the correction is out by a factor of R², and the energy by the square of that: (1 − (1 + e)R²)².
| Bumper radius | Energy after one hit, e = 0.8 |
|---|---|
| 1 | identical to the correct bounce |
| 5 | 1,936× |
| 10 | 32,041× |
| 20 | 516,961× |
The first row is why this bug survives testing. At radius 1 the raw vector already is a unit normal, so the wrong function and the right one return exactly the same thing — a test written against a radius-1 bumper cannot see the bug at all. At a real bumper radius of 20 it multiplies the energy by 516,961, which is the ball leaving through the table in a single frame. It grows as the fourth power of the radius.
Mistake two: a kick that never stops — which does not run away
Real bumpers add energy deliberately; that is what makes them bumpers. Add a fixed kick k on every contact and each head-on hit maps v to e·v + k, whose fixed point is k / (1 − e). It does not explode. It converges:
| Kick | Restitution | From speed 1 | From speed 5,000 | k / (1 − e) |
|---|---|---|---|---|
| 50 | 0.8 | 250.0 | 250.0 | 250.0 |
| 150 | 0.8 | 750.0 | 750.0 | 750.0 |
| 50 | 0.5 | 100.0 | 100.0 | 100.0 |
Compare the third and fourth columns. A ball starting at 5,000 is pulled down to exactly the speed a ball starting at 1 is pushed up to — the kick is an attractor, not a runaway. Which is arguably worse: the table does not blow up in a way you would notice while testing, it just settles at one speed and stays there, and at k = 150 with e = 0.8 that speed is 750.
The one case that genuinely diverges is a perfectly elastic table, e = 1, where nothing ever removes the kick and the fixed point is infinite. The fix is not to drop the kick but to cap it — kick only while the ball is below the speed you want the table to run at.
How to use
- Pick a collision resolver and press Launch.
- The correct one settles down as the ball loses energy.
- The kick model converges on one speed and stays there.
- The un-normalised normal throws the ball off the table at once.
- Press New table for a different bumper layout.
Frequently asked questions
What is the correct bumper collision formula?
v prime equals v minus (1 + e) times (v dot n) times n, where n is a UNIT vector along the contact normal and e is the restitution. It reflects the part of the velocity heading into the bumper and leaves the sideways part alone, which is what makes a glancing hit glance.
Can that formula create energy?
No. Sweeping every restitution from 0 to 1, every contact angle, every approach angle and ten speeds — 4,528,251 approaching contacts — the energy went up zero times. The worst ratio seen is exactly 1, and that case is a perfectly elastic head-on hit, which is meant to conserve energy.
Then why does browser pinball gain energy?
Because of something done around the formula rather than the formula itself. The two usual culprits are using the raw centre-to-ball vector instead of a unit normal, and adding a bumper kick on every contact with nothing to cap it.
What does the un-normalised normal do?
It multiplies the energy by (1 minus (1 + e) R squared) all squared. At restitution 0.8 that is 1,936 times for a bumper of radius 5 and 516,961 times for radius 20 — the ball leaves through the table in one frame. It grows as the fourth power of the radius.
Why does that bug survive testing?
Because at radius 1 it does not exist. A vector of length one already is a unit normal, so the wrong function and the right one return exactly the same thing. A test written against a radius-1 bumper cannot see the bug at all.
Does a bumper kick make the ball speed run away?
No, and this surprised us. Each head-on hit maps v to e times v plus k, whose fixed point is k over (1 minus e). It is an attractor: a ball starting at 5,000 is pulled down to the same speed a ball starting at 1 is pushed up to. Only a perfectly elastic table, where nothing removes the kick, actually diverges.
So how do you fix the kick?
Cap it rather than remove it. Kick only while the ball is below the speed you want the table to run at. Left uncapped at k = 150 and e = 0.8 the table settles at 750, which does not look like an explosion while you are testing — it just becomes unplayable and stays that way.
🔒 This tool runs entirely in your browser. Nothing you enter is uploaded, logged, or stored.