Game loop animation with a bouncy ball
Let's get our feet wet with my favorite childhood example: a bouncing ball.
I must have built dozens of them back in my Turbo Pascal days using BGI. Endless afternoons playing with different parameters in my bouncy ball examples.
Yes, those Turbo Pascal and BGI are from the 80's. No, I'm not that old. I started young and with old equipment. Coding for DOS is easier when you're a kid than coding for Windows 95.
Try to figure it out on your own first. Then watch my solution. Best way to learn :)
Here's a sandbox I prepared for you earlier:
Remember that gravity is an acceleration pointing down. It impacts the speed of your ball, not its position directly.
- Render the ball
- Use an effect to start a timer with
d3.timer
(it's like setInterval but better) - Ensure you clean up with
timer.stop()
- Move the ball on each timer iteration (also known as a tick)
- Adjust the ball's speed to simulate gravity
How do you get the bounce effect at max_h
? Look at the direction vY
points.
My solution
The key part of my solution is this useEffect
that runs a game loop.
useEffect(() => {function gameLoop() {setBall((ball) => {let { y, vy } = ballif (y > max_h) {vy = -vy}return {y: y + vy,vy: vy + 0.1,}})}const t = d3.timer(gameLoop)return () => t.stop()}, [])
That's where all the important things happen.
Start the timer on component mount, make sure it stops when the effect re-runs. Game loop itself is a function that takes current ball state and updates it with middle school physics:
- if ground reached, invert velocity
- add velocity to position
- add gravity to velocity
And you get a bouncy ball ✌️
While powerful, this technique is tedious for most applications. We'll look at using transitions next. That way D3 can do the hard work for us.