In a previous post we saw one way to bounce a ball off walls, by using angles and rotation. In maths, there are often several ways to approach a problem, with different techniques that can be used to achieve the same result. In this post, I’m going to solve the same problem of bouncing off the walls, but using a different technique: the dot product.
Rethinking Bouncing
One way to think about bouncing off a wall is that the angle gets reflected around the surface normal (the dotted line), as we saw last time:
Another way to think about the bouncing is that the velocity parallel to the surface (perpendicular to the normal) is maintained, and the velocity perpendicular to the surface (parallel to the normal) is reversed. This can be seen in the diagram below — the coloured vectors on the left are equivalent to the sum of their dotted/dashed counterparts on the right, where the component parallel to the surface is kept constant, but the component perpendicular to the surface is reversed:
Implementing this for horizontal or vertical walls is easy, but how do you do this when the normal is at an arbitrary angle, such as the jaws of the pocket?
The Dot Product
What we need to do is be able to split a vector into two components: one being the distance in the direction along the normal, the other being the distance along a vector perpendicular to the normal. The easiest way to do this is to use something called the dot product. The dot product of two vectors refers to multiplying the X components together, and the Y components together:
By itself, this is of no use, but the dot product has an important theorem attached to it:
(where and
are vectors,
is the angle between them, and
is the length of the vector, which can be calculated using Pythagoras.) The reason this is useful is that if you have two vectors, calculating what is known as the “projection” of one on to another looks like this:
The distance along the new vector is , which from rearranging the dot product result, we know to be:
So, we can add a method to calculate the distance along a particular vector, using :
private double distAlong(double x, double y, double xAlong, double yAlong) { return (x * xAlong + y * yAlong) / Math.hypot(xAlong, yAlong); }
Get Bouncing
Our aim in this post is to bounce off walls. So we can use that distAlong method to calculate the distance along the normal, and reverse it. But we also need to calculate the distance along a vector perpendicular to the normal (parallel to the wall). How can we calculate a vector that’s perpendicular to the normal? It turns out that in 2D there’s a really quick, simple way to rotate a vector 90 degrees: swap the X and Y components and negate one of them (challenge for you: why/how does this work?). That gives our final code for doing the bouncing:
double normalX = w.getNormalX((int)newX, (int)newY, b.getRadius()); double normalY = w.getNormalY((int)newX, (int)newY, b.getRadius()); double distPerpWall = distAlong(vx, vy, normalX, normalY); double distParWall = distAlong(vx, vy, normalY, -normalX); //Bounce: distPerpWall = -distPerpWall; vx = distParWall * normalY + distPerpWall * normalX; vy = distParWall * -normalX + distPerpWall * normalY;
As a reminder of what that code is doing, here’s a final diagram. First (1), we calculate the normal (the black dashed line, below). Then (2) we split the incoming velocity, vx and vy, into the distance perpendicular to the wall (the orange dashed arrow, below) and the distance parallel to the wall (the orange dotted arrow, below). Next (3) we flip the direction of the dashed arrow to get the resulting blue arrows describing the velocity after the bounce, and (4) we convert the sum of those two vectors back into the new velocity, which we store back into vx and vy:
I haven’t bothered to upload the new scenario, because it behaves identically to the previous scenario! Next post we will finally implement collisions between the balls (which will again use the dot product), and then I will upload the final scenario featuring this code and the ball collision code.
Comments on: "Bouncing Off The Walls, More Productively" (2)
[…] between balls: we just need to check if two circles are overlapping. We’ve also seen how to resolve a collision when bouncing a ball off a wall (i.e. one moving object and one stationary). The final piece of the puzzle is just to put it all […]
vx = distParWall * normalY + distPerpWall * normalX;
vy = distParWall * -normalX + distPerpWall
how does these codes works?