How it works
Each ball is modelled as a rigid disk with mass proportional to its area:
$$m = \pi r^2$$
Euler integration
Position and velocity are updated each frame using Euler integration with timestep $\Delta t$:
$$\mathbf{v}_{n+1} = \mathbf{v}_n + \mathbf{g} ,\Delta t$$
$$\mathbf{x}_{n+1} = \mathbf{x}_{n} + \mathbf{v}_{n+1} ,\Delta t$$
where $\mathbf{g} = (0, g)$ is the gravity vector (positive $y$ points down on screen).
Collision detection
Two balls $A$ and $B$ with radii $r_A$, $r_B$ and centres $\mathbf{x}_A$, $\mathbf{x}_B$ are overlapping when:
$$|\mathbf{x}_B - \mathbf{x}_A| < r_A + r_B$$
The collision normal is the unit vector pointing from $A$ to $B$:
$$\hat{\mathbf{n}} = \frac{\mathbf{x}_B - \mathbf{x}_A}{|\mathbf{x}_B - \mathbf{x}_A|}$$
Impulse resolution
The relative velocity along the normal tells us whether the balls are approaching:
$$v_\text{rel} = (\mathbf{v}_A - \mathbf{v}_B) \cdot \hat{\mathbf{n}}$$
If $v_\text{rel} \leq 0$ the balls are separating — no impulse needed. Otherwise, the scalar impulse magnitude is:
$$j = \frac{-(1 + e), v_\text{rel}}{\dfrac{1}{m_A} + \dfrac{1}{m_B}}$$
where $e \in [0, 1]$ is the coefficient of restitution — the ratio of post-collision to pre-collision relative speed. $e = 1$ is perfectly elastic (no energy lost), $e = 0$ is perfectly inelastic.
Velocities are updated by applying equal and opposite impulses:
$$\mathbf{v}_A \mathrel{+}= \frac{j}{m_A}\hat{\mathbf{n}}, \qquad \mathbf{v}_B \mathrel{-}= \frac{j}{m_B}\hat{\mathbf{n}}$$
Kinetic energy
The total kinetic energy displayed in the stats bar is:
$$E_k = \sum_i \frac{1}{2} m_i |\mathbf{v}_i|^2$$
Watch it drop immediately after the “Explode” burst as restitution dissipates energy through wall and ball-ball collisions.
Simulation
Controls reference
| Control | Effect |
|---|---|
| Balls | Number of rigid disks spawned |
| Gravity | Downward acceleration in px/s² |
| Restitution | Energy retained per collision (1 = elastic, 0 = inelastic) |
| Ball size | Radius in pixels — also scales mass as πr² |
| Respawn | Randomise positions and velocities |
| Explode | Apply outward impulse from centre |