Workshop › Pool › Step 29 of 33
With the physics this precise, we can predict the shot. The ghost ball is where the cue ball will be when it first
touches another ball. For each ball: how far along the aim line it is (t), and how far to the side (side, squared). If
the side distance is less than 2R, the cue ball will hit it.
```js
// Where the cue ball will first touch another ball along the aim: the "ghost ball".
function ghost() {
const ux = Math.cos(aim)
const uy = Math.sin(aim)
let first = null
for (const b of balls) {
if (b === cue) continue
const dx = b.x - cue.x
const dy = b.y - cue.y
const t = dx * ux + dy * uy // how far along the aim line the ball is
const side = dx * dx + dy * dy - t * t // squared distance from the line
if (t <= 0 || side >= R * R * 4) continue
const hit = t - Math.sqrt(R * R * 4 - side)
if (!first || hit < first.hit) first = { hit, ball: b, x: cue.x + ux * hit, y: cue.y + uy * hit }
}
return first
}
```(ux, uy) is the aim direction with length 1.t is a dot product: how far along the aim the ball's centre is. side is the squared distance from the line
(Pythagoras: distance² − t²).t <= 0) or too far to the side: no hit.2R, so the cue ball stops sqrt(4R² − side) before reaching t. The nearest hit wins; (x, y)
is the ghost ball's centre.Above function draw() { write ghost with its comment, and leave an empty line after it.
Skills: Collision detection, Functions
← Smaller steps Draw the ghost ball →