2
votes

I have a small physics program that has a large number of balls of equal size and mass that bounce around in 2D space. The problem I am having is that after most collisions, the momentum is increased, though sometimes it decreases.

public static void Collide(Ball b1, Ball b2)
{
  Vector2 dist = b2.Position - b1.Position;
  float distance = dist.Length();
  Vector2 normal = dist * (1 / distance); //get collision normal
  float dotprod = Vector2.Dot(normal, b1.Velocity - b2.Velocity);
  Vector2 impulse = normal * dotprod; //compute the impulse in the direction of our normal
  //ball positions at collision: (.7071, 0.2929); (1,0)
  //initial velocities: (2, 0); (0, 0) : total momentum = 2
  b1.Velocity -= impulse;
  b2.Velocity += impulse;
  //new velocities: (1,1); (1, -1) : total momentum = ~2.828
}

This is the collision algorithm after I simplified it a lot because all the balls are the same size and mass. I've tried several different algorithms and they all produce the same results. In a system with 100 balls, the total momentum of the system climbs to about 90 and levels off when I start with 1 ball with momentum 10 (elastic walls, no friction). Based on the number of algorithms I have tried, it almost seems like this is how it's supposed to work, but it seems this is violating conservation of momentum?

Some of the algorithms I've tried: http://www.vobarian.com/collisions/2dcollisions2.pdf (from Wikipedia) and Ball to Ball Collision - Detection and Handling

2

2 Answers

4
votes

You seem to be mistaking the sum of the magnitudes of the individual momenta for the total momentum itself. The momentum of a material point is a vector quantity:

p = m.v

and the total momentum is the vector sum of all individual momenta:

P = ∑ mi.vi = m ∑ vi

(as in your case all masses are equal)

The kinetic energy is a scalar quantity:

K = (1/2) m.v2 = p2 / (2m)

and the total kinetic energy is again the sum of all individual kinetic energies:

K = ∑ (1/2) mi.vi2 = (m/2) ∑ vi2

In an elastic collision both K and P are conserved. This holds true in your example. Indeed, your balls' initial velocities are (2,0) and (0,0), therefore:

Pbefore = m * ((2,0) + (0,0)) = (2m, 0)

Kbefore = (m/2) * ((2,0).(2,0) + (0,0).(0,0)) = (m/2) * (4 + 0) = 2m

The final velocities are (1,1) and (1,-1), therefore:

Pafter = m * ((1,1) + (1,-1)) = (2m, 0)

Kafter = (m/2) * ((1,1).(1,1) + (1,-1).(1,-1)) = (m/2) * (2 + 2) = 2m

Obviously Pafter = Pbefore and Kafter = Kbefore.

1
votes

Instead of: float dotprod = Vector2.Dot(normal, b1.Velocity - b2.Velocity); Try this: Vector2 velocityDif = b1.Velocity - b2.Velocity; float dotprod = Vector2.Dot(normal, Vector2.Normalize(velocityDif));