A more sophisticated ball-paddle collision algorithm for Breakout?

I have a simple breakout game I'm working on. The collision code is solid; things bounce as they should and don't pass through things or do other funkiness, but the reflection is a bit simplistic. As a result, it's easy to get into a state where the ball gets stuck in a loop such that the last blocks cannot be hit without dying to break the loop.

Currently, the paddle collision code reflects the Y speed, and mirrors the X speed depending on what side of the paddle it hits:

        // Check for paddle collisions
double ballCenter = m_ball.rect().getX() + (m_ball.rect().getWidth()/2);

m_ball.setSpeedY(m_ball.speedY() * -1);

m_ball.setSpeedX(Math.abs(m_ball.speedX()));
} else {
m_ball.setSpeedX(-Math.abs(m_ball.speedX()));
}
}


Is there any way I could make the algorithm more "interesting", and tighten up the control so the ball doesn't keep get stuck bouncing in the same square?

Use a sliding scale to modify the X speed depending on the location on the paddle.

Set some sort of constant for a max X speed change. If the ball hits on the very right side of the paddle, add this constant to the X speed. If it hits on the very left side of the paddle, subtract this constant from the X speed. If it hits in the very middle of the paddle, do not affect the X speed.

Anywhere in between, use a sliding scale to determine the amount to add or subtract to the X speed.

A lot of break out games will introduce "spin". If the paddle is moving it will influence the X direction of the ball in the direction the paddel is moving.

Jonathan,

I would do as Erick suggests, but I would be careful to make sure the X and Y speed components remain interlocked, otherwise the ball's overall speed will change simply from a collision with the paddle, which is unrealistic physics.

So I would first compute the ball's overall speed from .speedX() and .speedY() (using the Pythagorean theorem), then compute the new X speed from the position of the ball relative to the paddle, and then set the Y speed dependent on a function of the new X speed and the original overall speed, so that the ball simply changes direction (in an infinite number of possible angles) but always maintains the same overall speed.

To put that more concretely, I would do it like this:

if ((m_ball.rect()).intersects(m_paddle.rect())) {
double ballWidth = m_ball.rect().getWidth();
double ballCenterX = m_ball.rect().getX() + ballWidth/2;
double speedX = m_ball.speedX();
double speedY = m_ball.speedY();

// Applying the Pythagorean theorem, calculate the ball's overall
// speed from its X and Y components.  This will always be a
// positive value.
double speedXY = Math.sqrt(speedX*speedX + speedY*speedY);

// Calculate the position of the ball relative to the center of
// the paddle, and express this as a number between -1 and +1.
// (Note: collisions at the ends of the paddle may exceed this
// range, but that is fine.)

// Define an empirical value (tweak as needed) for controlling
// the amount of influence the ball's position against the paddle
// has on the X speed.  This number must be between 0 and 1.
final double influenceX = 0.75;

// Let the new X speed be proportional to the ball position on
// the paddle.  Also make it relative to the original speed and
// limit it by the influence factor defined above.
speedX = speedXY * posX * influenceX;
m_ball.setSpeedX(speedX);

// Finally, based on the new X speed, calculate the new Y speed
// such that the new overall speed is the same as the old.  This
// is another application of the Pythagorean theorem.  The new
// Y speed will always be nonzero as long as the X speed is less
// than the original overall speed.
speedY = Math.sqrt(speedXY*speedXY - speedX*speedX) *
(speedY > 0? -1 : 1);
m_ball.setSpeedY(speedY);
}


Note: As time goes on, rounding errors will cause the overall speed to drift slowly from its original value. The desired overall speed might be something you want to add as member data to m_ball (rather than calculating it each time here), or it might be something you want to allow to speed up and slow down according to other gameplay factors.

• It's a common game mechanic to slowly speed the ball up until someone loses. Otherwise you could play forever. – Erick Robertson Jul 22 '15 at 1:14
• That's a good point! – Todd Lehman Jul 22 '15 at 17:33