Jonathan,
Eu faria o que Erick sugere, mas tomaria cuidado para garantir que os componentes de velocidade X e Y permaneçam interligados; caso contrário, a velocidade geral da bola mudará simplesmente de uma colisão com a raquete, que é uma física irrealista.
Então, eu primeiro calculava a velocidade geral da bola de .speedX()
e .speedY()
(usando o teorema de Pitágoras), depois calculava a nova velocidade X a partir da posição da bola em relação à raquete, e então definia a velocidade Y dependente de uma função da nova velocidade X e a velocidade total original, de modo que a bola simplesmente mude de direção (em um número infinito de ângulos possíveis), mas sempre mantenha a mesma velocidade geral.
Para colocar isso de maneira mais concreta, eu faria assim:
if ((m_ball.rect()).intersects(m_paddle.rect())) {
double ballWidth = m_ball.rect().getWidth();
double ballCenterX = m_ball.rect().getX() + ballWidth/2;
double paddleWidth = m_paddle.rect().getWidth();
double paddleCenterX = m_paddle.rect().getX() + paddleWidth/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.)
double posX = (ballCenterX - paddleCenterX) / (paddleWidth/2);
// 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);
}
Nota: Com o passar do tempo, os erros de arredondamento farão com que a velocidade geral se desvie lentamente do valor original. A velocidade geral desejada pode ser algo que você deseja adicionar como dados de membro m_ball
(em vez de calculá-lo sempre aqui), ou pode ser algo que você deseja permitir que acelere e desacelere de acordo com outros fatores de jogo.