Olá pessoal, tudo bom?
Eu achei interessante as várias soluções que o pessoal criou para resolver esse bug da bola presa na raquete, então eu resolvi compartilhar a minha solução também.
Então, pelo o que eu pude observar, esse bug acontece porque, dependendo da posição que a bola atinge a raquete, quando a bola é rebatida pela raquete, no próximo frame do jogo a bola continua sobrepondo o desenho da raquete. Dessa forma o jogo registra outra colisão e inverte o sentido da "velocidadeXBola" novamente e assim cria um loop de inversão do "velocidadeXBola" que só termina quando a bola sai pela lateral da raquete.
Tendo isso em mente eu fiz o seguinte:
//Variável global
let jaRebateu = false;
function verificaColisaoRaquete() {
let colidiu = collideRectCircle(xRaquete, yRaquete, comprimentoRaquete, alturaRaquete, xBola, yBola, diametroBola);
if (colidiu && !jaRebateu) {
velocidadeXBola *= -1;
jaRebateu = true;
} else if (!colidiu && jaRebateu) {
jaRebateu = false;
}
}
Utilizando basicamente o mesmo código que o Prof. Guilherme escreveu nas aulas, eu fiz algumas pequenas adições, mas o segredo é a variável "jaRebateu", que eu utilizo pra controlar a quantidade de vezes que a função "verificaColisaoRaquete" realiza a inverção do "velocidadeXBola".
O que acontece aqui é que, quando a bola colide com a raquete, a função "collideRectCircle" irá definir o valor de "colidiu" para true, como foi visto nas aulas, em seguida o "if" da função irá verificar se o valor de "colidiu" é true e se a bola ainda não rebateu na raquete através do "!jaRebateu" (normalmente o valor false é o que indica isso, mas como o "if" só executa o seu código quando todas as condições dão true, eu adicionei o "!" para inverter o valor booleano da variável). Caso esse seja o primeiro frame em que ocorre essa colisão entre a bola e a raquete, o "if" deve executar seu código normalmente, invertendo o sentido de "velocidadeXBola" e também mudando o valor de "jaRebateu" para true.
Agora, se nos próximos frame a bola ainda estiver sobrepondo o desenho da raquete, o jogo irá realizar o mesmo processo de antes, porém o código do "if" que inverte o "velocidadeXBola" não será executado, pois dessa vez o valor de "jaRebateu" será true e quando o "if" verificar o "!jaRebateu", resultará false.
Por fim, depois que a bola deixar de colidir com a raquete, o jogo irá validar um outro "if", o qual verifica se não há mais colisão através do "!colidiu" e se o "jaRebateu" ainda está como true, executando assim um código que retorna o "jaRebateu" para o seu estado inicial.
Dessa forma, sempre que a bola colidir com a raquete, ela sempre será rebatida uma única vez, mesmo que após a rebatida a bola continue em contato com a raquete.