Sinking Your Shot:
Now that you have determined that your circles collide, you want to have them bounce off of each other in a realistic manner, taking into account their relative mass and speed. To solve this, we are going to rely on some simple laws of physics, specifically the conservation of momentum and the conservation of energy.
Figure 14: Bounce
Conservation of Momentum states that the total momentum of the system before the collision is equal to the total momentum in the system after the collision. If we represent the momentum of a circle to be P = M * V, where M is the circles mass and V is its movement vector, then we can derive the equation:
where v1'and v2' are the movement vectors of circle 1 and 2 respectively after the collision. Since the second circle gains any momentum lost by the first, we can represent the difference between the momentums of the balls before and after by the same vector, deltaP.
here is where the difference between reality and simulation comes into
play. If these two spheres were the rubber balls we all used in gym class
in high school, when they hit they would deform. This deformation would
increase the area where the balls are touching, and some of the energy
would be lost in that deformation. Other amounts of it would be lost in
spin. But in this simulation, we are assuming the balls to be rigid, frictionless,
perfect spheres. A common real-world example of this type might be the
steel balls hanging from a frame that collide with each other to demonstrate
action-reaction; because they are so rigid, very little of their momentum
is lost when they collide, and so when you set one ball swinging it takes
some time for them all to stop.
So in our simulation of perfect rigid spheres, the only transference of momentum can occur along the single point of contact, as illustrated in figure 13. Therefore, we can break deltaP into a unit vector N that points down the line of contact, and a scalar P representing the magnitude of deltaP. So, if we apply this to the equations above, we can solve for the new movement vectors of the circles and get:
So, if we
can solve for P, we can calculate the new movement vectors.
Now look back at figure 13, and notice that v1 and v2 can be represented by the sum of two vectors: one that is parallel to the line along which momentum is exchanged, and one that is perpendicular to it. Using this information, we can represent v1, v1', v2, and v2' by:
a1, a2, b1, and b2 are scalars, N
is the same N as mentioned before, and Q is
the normalized vector perpendicular to the line along which momentum is
exchanged and on the same plane as N and the movement vector.
Substituting v1 in equation 1 for the value of v1 in equation 3, and v2 in equation 2 for the value of v2 in equation 3, we get:
And since v1' = a1'*N + b1'*Q and v2' = a2'*N + b2'*Q, we can see that
Now we can use the Conservation of Energy to solve for P. The equation for kinetic energy is:
Since energy is conserved, the total energy before the collision must equal the total energy after the collision:
Using the movement vector as the hypotenuse of a right triangle, we can substitute:
Substituting equation 4 for a1', b1', a2' and b2', we get:
Note that the b1 and b2 terms in equation 7 drop out of the equation. With an equation in terms of m1, m2, a1, a2, and P, we have an equation with variables that are either given or can be calculated from what was given, except for P. So if we solve for P, we will be able to plug in the known variables, derive P, and then use P to calculate the new movement vectors. Equation 8 shows equation 7 after solving for P.
So, plugging this into Equations 1 & 2:
Notice that for both v1' and v2' the term in the () brackets is the same, so you only need to calculate that once. With that done, you can calculate v1'and v2'. Now that we've done the math for this, the code to implement the results is very short and quick. The variable optimizedP in the code refers to the term in brackets above.
// First, find the normalized vector n from the center of
// circle1 to the center of circle2
Vector n = circle1.center - circle2.center;
// Find the length of the component of each of the movement
// vectors along n.
// a1 = v1 . n
// a2 = v2 . n
float a1 = v1.dot(n);
float a2 = v2.dot(n);
// Using the optimized version,
// optimizedP = 2(a1 - a2)
// m1 + m2
float optimizedP = (2.0 * (a1 - a2)) / (circle1.mass + circle2.mass);
// Calculate v1', the new movement vector of circle1
// v1' = v1 - optimizedP * m2 * n
Vector v1' = v1 - optimizedP * circle2.mass * n;
// Calculate v1', the new movement vector of circle1
// v2' = v2 + optimizedP * m1 * n
Vector v2' = v2 + optimizedP * circle1.mass * n;
These techniques will allow you use spheres with a higher degree of accuracy than is probably necessary if your spheres are all bounding spheres. Precise collisions between spheres become important when simulating things likes pool balls or marbles, or potentially rocks in a landslide. But for spheres bounding characters, for example, you might not care what angle two colliding characters would bounce away at. However, parts of these methods are fast enough to be useful if only to determine that a collision was avoided. But who knows; using a pumped-up space marine as a cue ball just might be humorous enough to do…
Special thanks to Dave Baum for his help with collision response.