My Profile Photo

Cloud Oak


Here I will occasionally write about stuff I consider interesting.


Pachelballs

When I was a kid, I really enjoyed this game called Electroplankton. Especially the game mode called Hanenbow, where you launched small tadpoles onto leaves. On impact the leaves would emit glockenspiel sounds, and create a nice sounding melody. Here’s what it looked like:

I wondered, how hard could it be to implement something similar? If you just want to see the animation, click here. If you’re interested in the background, read on!

Concept

Basic Concept Drawing The basic idea: Cannon, Balls, Bouncers

First we have a cannon that shoots out balls at a certain frequency. These balls then fly through a field of bouncers, that act like small trampolines for the balls. Upon hitting a bouncer, a ball will emit a certain tone.

Physics

We’re going to be using the wonderful CindyJS Framework, that does a lot of the heavy lifting behind the scenes.

Ball flying physics is easy. A ball with position and velocity will be updated in two steps:

  • , where is the timestep and is the gravity vector.

The collisions with the bouncers are where it gets tricky. First of all, how do we detect a collision?

Collision Detection

Say a ball is updated from position to position . We want to check if it collides with a bouncer during that update. A bouncer is given by the endpoints and .

One can see that we have a collision if and only if these two conditions are fulfilled:

  • and lie on opposing sides of the line .
  • and lie on opposing sides of the line .

There is a neat way of calculating which side of a line a point is on using determinants. The determinant

will have a positive sign if lies left of the line , and a negative one if it lies on the right:

The sign of the determinant tells us if is left or right of the line

So a collision is equivalent to having both and .

Upon collision, we want to play a sound and reflect the ball. This is done by setting the velocity , where is the bouncer’s normal.

Music

If we were to just emit random tones, the result would be disharmony. We must therefore pick the tones we play from some harmonic distribution. The easiest way to do this is to limit the tones to a certain chord. We can then change the chords over time, to get a nice little tune.

As you have probably guessed from the title, we’ll be using the chord progression from Pachelbel’s Canon.

Pachelbel Canon (Transposed) Chord Progression of Pachelbel’s Canon

CindyJS has a MIDI Interface, that just enumerates musical notes starting with C0. So our chord progression can be transcribed into

chords = [
    [63, 68, 72], // Ab
    [63, 67, 70], // Eb
    [60, 65, 68], // Fm
    [60, 63, 67], // Cm
    [56, 61, 65], // Db
    [56, 60, 63], // Ab
    [56, 61, 65], // Db
    [58, 63, 67]  // Eb
];

Each one of the bouncers will play a tone based on this chord table, where the row will cycle through time.

Finished animation

Putting it all together, we get this nice little interactive animation.

If you’re interested in the source code, you can find it here.