Reference Frames
In the last chapter we created a function that would handle a one dimensional elastic collision where one body was at rest. But what if both bodies are moving (still in one dimension)? Well, there is a concept from physics that helps us resolve this: an inertial reference frame. There is a lot of literature on this concept going back hundreds of years but at it’s heart it is quite easy to grasp. The idea is that there is no absolute frame of reference and that the laws of physics will still appear to be consistent even when the observer is moving in a uniform manner relative to other bodies in the system.
The standard example for this concept it to imagine a person in a moving railway carriage throw a ball to another person. To the people in the carriage the ball moves at a certain speed until it is caught – then it stops moving. To an observer on the railway platform, the ball is moving at the speed of the train plus the speed that it is thrown. When it is caught, it still appears to be moving at the speed of the train to the observer on the platform.
The observers in the carriage and on the platform are both right about the speed of the ball. It’s just that they occupy different frames of reference. That is the concept we are going to use here.
Suppose we imagine a frame of reference (FoR) that is travelling along at the same direction and speed as ball2. In this FoR ball2 would appear to be at rest. But how fast is ball1 moving in this FoR. That’s easy – we just do a (vector) subtraction of the velocity of ball2 from both ball1 and ball2. Then ball2 is at rest and we have the relative velocity of ball1.
Now that we have moved the balls into a new FoR we can apply the original elastic collision function to get the new velocities in the new FoR. The final thing to do is to return our balls to the original FoR.
The Code
So what does all this mean for our code? It means all we need to do is change our handleCollision() function to manage the switching to (and back from) a frame of reference where ball2 is stationary. Like this…
function handleCollision(ball1, ball2) {
// Change to a new FoR in which ball2 is at rest
var vel_adj = ball2.vel.copy()
ball1.vel.sub(vel_adj)
ball2.vel.sub(vel_adj)
// Handle the collision in the new FoR
let [v1f, v2f] = elastic_collision(ball1.mass, ball2.mass, ball1.vel.x);
ball1.vel.x = v1f;
ball2.vel.x = v2f;
// Switch back to the original FoR
ball1.vel.add(vel_adj)
ball2.vel.add(vel_adj)
// Remove potential overlap
while (areColliding(ball1, ball2)) {
ball1.update();
ball2.update();
}
}
Overlap
What is that bit at the end of the function about removing potential overlap? Well, now that our sketch can keep running and the balls can wrap around the edges of the sketch we will get a lot more collisions happening while the sketch runs. We need to remember that while this function is running the two balls are actually intersecting with each other. The final velocities that we calculate might be enough to separate the balls when we next call the update() function, but this is not guaranteed. So this little loop just keeps calling the update() function on each ball until we are sure that they are no longer intersecting.
We can write a more elegant solution to this problem in the next chapter.
The sketch
So now we can allow the balls to wrap around the edge of the screen because our code handles both balls moving…
Click the sketch a few times to generate different initial velocities and see how the total momentum and energy changes but are still conserved after each collision.
We’ve really made some progress now – the balls are colliding and bouncing in a realistic way and we can see that the total energy and momentum of the system is being conserved. Now we just need to expand our collision handling into two dimensions…