We work on a Breakout game for school all the time. This how we do it. Note that this is from within a Ball class so every time to see this think Ball.
The following Bounce method calculates and applies the
velocity and spin change from a bounce of the Ball.
The "factors" indicate how to translate speeds in the
x and y directions into the speed parallel to the surface. If we
orient our view so that the Ball is moving down toward the surface,
the speed parallel to the surface is positive if movement is to the
right.
The equations are derived from the physical analysis presented in:
Richard L. Garwin, "Kinematics of an Ultraelastic Rough Ball",
American Journal of Physics, 37, 88-92, Jan. 1969. This determines
behavior for a perfectly bouncy ball (elastic collision) with spin
that does not slip/slide when bouncing. A real-world analog is the
Superball product by Wham-O.
We make two modifications / specializations:
1) Since we operate in two dimensions, our "ball" is a disc. This
makes the moment of inertia
1/2 * M * R^2
. In the conventions of
Garwin's paper, this means that alpha = 1/2.
Garwin does not consider collision with a moving surface. However,
it is easy to adjust things by considering movement relative to the
frame of the moving surface. We simply subtract the speed of the
surface from the Ball's parallel movement before computing what
happens in the collision, and then add the speed back afterwards.
In Garwin's notation, we end up with:
Ca = -1/3 Cb - 4/3 Vb + 4/3 Vs
Va = -2/3 Cb + 1/3 Vb + 2/3 Vs
Here Va and Vb are the speed of the Ball parallel to the surface
after and before the collision, respectively. Vs is the speed of
the surface. Ca and Cb are R * spin of the Ball, after and before
the collision, respectively. (In Garwin's notation, C = R * omega,
where omega is the spin.)
/*
@param xFactor an int, -1, 0, or 1, giving the factor by which to
multiply the horizontal speed to get its contribution to the speed
parallel to the surface
@param yFactor an int, -1, 0, or 1, giving the factor by which to
multiple the vertical speed to get its contribution to the speed
parallel to the surface
@param speed a double, giving the speed of the surface; positive
is movement to right if we consider the surface as being horizontal
with the Ball coming down onto it
*/
private void bounce (int xFactor, int yFactor, double speed) {
// can get stuck, so add a random component to the speed
speed += 0.03 * (random.nextFloat() - 0.5);
// obtain parallel / normal speeds for horizontal and vertical
double vParallel = xFactor * this.getHorizontalSpeed() +
yFactor * this.getVerticalSpeed();
double vNormal = xFactor * this.getVerticalSpeed() -
yFactor * this.getHorizontalSpeed();
double radius = this.getImage().getHeight() / 2.0D;
// determine Garwin's Cb and Vb
double cBefore = radius * spin;
double vBefore = vParallel;
// determine Garwin's Ca and Va
double cAfter = (-1.0D/3.0D) * cBefore + (-4.0D/3.0D) * vBefore + (4.0D/3.0D) * speed;
double vAfter = (-2.0D/3.0D) * cBefore + ( 1.0D/3.0D) * vBefore + (2.0D/3.0D) * speed;
// apply direction reversal to normal component
double vNAfter = -vNormal;
// determine horizontal and vertical speeds from parallel and normal components
double vHAfter = xFactor * vAfter - yFactor * vNAfter;
double vVAfter = xFactor * vNAfter + yFactor * vAfter;
// update the Ball's state
this.setHorizontalSpeed(vHAfter);
this.setVerticalSpeed(vVAfter);
this.spin = cAfter / radius;
}