2
\$\begingroup\$

I'm trying to learn HTML canvas and was working on a basic physical simulation, where a number of balls are drawn and set in motion, and the program simulates them colliding and bouncing off the walls and each other.

Here's the simulation.

Each ball is initially given a random position, direction, and a constant starting velocity. For simplicity, a ball's mass is simply equal to its radius. The velocity vectors are stored as (x,y) instead of polar coordinates to make the calculations simpler and the simulation faster, but this apparently has unintended consequences.

In the simulation linked above, I'm starting with ten balls, and each ball has an initial velocity magnitude of 3, so the total initial "speed" of the system should be 30 (= 10 * 3). On each frame, I calculate the total speed of all the balls and read it out in a form field, and with uniform balls of size 10, the total speed seems to stay a few units under 30. The same is true of the min and max radius are decreased so all the balls are size 5, or increased to 20: the total speed stays relatively uniform.

However, interesting things happen when the balls vary in size. If the minRadius is changed to 5 and maxRadius to 15, for example, you'll notice that the total speed of the system starts climbing over time. The bigger the difference, the faster the speed grows out of control.

SO my first guess is that I screwed up the physics, but I can't figure out how. My other guess is that this is caused by accumulating floating point error, but it's interesting that it only grows upwards, and never towards zero. Also, it does seem to have a limit; while it constantly fluctuates, it seems to be capped at some value related to the delta between the minimum and maximum ball size.

My question is really to understand why this is happening? Did I just screw up something simple, or is something more sinister going on?

\$\endgroup\$
2
\$\begingroup\$

First , your

polarToComponent(magnitude, angle) {
    return {
      x: magnitude * Math.cos(angle),
      y: magnitude * Math.sin(angle)
    };

Called for each ball at start time, introduce a numeric error. So you must calculate the total velocity before starting simulation and compare with that instead of 30.

Second your

function checkCollisions()

called each frame introduce some other numeric errors () for each collision, sum it all and you get the difference you see.

Assuming all masses are equal. Try to calculate the starting total velocity SV, then calculate the mean total velocity over N frames and compare that with SV.

Regarding

However, interesting things happen when the balls vary in size. If the minRadius is changed to 5 and maxRadius to 15, for example, you'll notice that the total speed of the system starts climbing over time. The bigger the difference, the faster the speed grows out of control.

may be there's an error here:

    ballOne.velocity.x = ballOne.velocity.x + (scalarOne * direction.x);
    ballOne.velocity.y = ballOne.velocity.y + (scalarTwo * direction.y);
    ballTwo.velocity.x = ballTwo.velocity.x - (scalarOne * direction.x);
    ballTwo.velocity.y = ballTwo.velocity.y - (scalarTwo * direction.y);

should be : (forked here)

    ballOne.velocity.x = ballOne.velocity.x + (scalarOne * direction.x);
    ballOne.velocity.y = ballOne.velocity.y + (scalarOne * direction.y);
    ballTwo.velocity.x = ballTwo.velocity.x - (scalarTwo * direction.x);
    ballTwo.velocity.y = ballTwo.velocity.y - (scalarTwo * direction.y);

enter image description here

Finaly: with different ball masses comparing the total speed is inappropriate. You must compare the total momentum mass*velocity

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.