He estado haciendo pruebas y me cuesta bastante depende de las matematicas y la vision espacial que cada uno tengamos jeje. Lo que he entendido es que se hacen estas ejecuciones.
Establece el ángulo de partida en 325º (en grados sexagesimales es más fácil de ver, aunque luego para el cálculo matemático usa radianes porque es la forma de trabajar los grados que se suele usar en matemáticas y que usa Java, pero para la lógica nos podemos olvidar de los radianes).
Si establecemos el ángulo de partida en 0, la bola sale en horizontal hacia la derecha y rebota en la pared derecha adoptando movimiento en sentido 180º (pi radianes) con lo que sale rebotada hacia la izquierda en horizontal, y al llegar a la pared izquierda vuelve a rebotar igual, con lo cual lo que hace es moverse siempre en horizontal.
Si establecemos el ángulo de partida en 90, la bola sale en vertical hacia abajo y rebota en la pared inferior adoptando movimiento en sentido 180º (pi radianes) con lo que sale rebotada hacia arriba en vertical, y al llegar a la pared superior vuelve a rebotar igual, con lo cual lo que hace es moverse siempre en vertical.
Con esto ya tenemos cómo trabaja los ángulos que es 0 horizontal derecha 90 abajo 180 horizontal izquierda 270 arriba 360 equivale a 0 completando "una vuelta", 450 equivale a 90 ya que sería como una vuelta y noventa más con lo cual llegamos al mismo angulo (450%360=90 es decir es el resto y % es el operador módulo que devuelve el resto de una división, 540 equivale a 180 ya que 540%360 = 180 es el resto) y así sucesivamente hasta el valor que queramos. Por ejemplo 1210º equivale a 130º porque el resto de dividir 1210 entre 360 es 130 es decir 1210%360 = 130
Para mover la bola primero comprueba si hay rebote:
if (xPosition < radius) { //Bola rebota con pared izquierda
angle = 540 - angle;
}
if (xPosition > drawingPanelDimension.width - radius) { //Bola rebota con pared derecha
angle = 540 - angle;
}
if (yPosition < radius) { //Bola rebota con pared inferior
angle = 360 - angle;
}
if (yPosition > drawingPanelDimension.height - radius) { //Bola rebota con pared superior
angle = 360 - angle;
}
angle %= 360; // Operador modulo resto de division entre 360
Haya habido o no rebote termina calculando el ángulo como angle %= 360; que si no me equivoco es lo mismo que angle = angle % 360, es decir, el valor de angle es el resto de dividir angle entre 360. Para el valor de partida 325 al dividir entre 360 el resto es 325, de modo que la bola sigue siempre en el ángulo en que esté hasta llegar a rebotar con una pared.
Dado que 270 equivale a vertical y 360 hacia la derecha, con 325 está tomando un ángulo que no es exactamente el intermedio entre ambos que seria 315º, sino un poco superior, con lo cual la bola sale hacia arriba y hacia la derecha (ligeramente más hacia arriba que hacia la derecha).
La primera pared a la que llega es la derecha y cuando esto ocurre hace el calculo angle = 540 - angle; que devuelve 215º y al aplicar angle %= 360; lo que hace es transformarlo a un valor entre 0 y 360 pero aquí sigue resultando 215. Aqui 540 equivale a 180. Si la bola fuera con 0 de partida, al restar 0 a 540, queda 540, que al ser 180, implica un rebote formando un angulo de 180º respecto al ángulo inicial. Lo que hace es calcular un ángulo simétrico respecto al angulo que traía respecto al eje y. Por ejemplo para 30º el simétrico sería 180-30 = 150º y esto es lo que ocurre si hacemos 540-30 = 510 y si ahora hacemos el módulo entre 360 tenemos 510%360 = 150º. Así restando a 540 el angulo con el que venía obtenemos el ángulo "simétrico" respecto al eje y, lo cual genera un efecto de rebote natural.
La idea como yo la veo es: si la bola rebota con pared derecha o izquierda, el nuevo ángulo es la diferencia entre 540 (equivale a 180) y el ángulo que traía, lo que equivale a mantener la componente vertical y hacer opuesta la componente horizontal, es hacer una simetría respecto al eje vertical. Si la bola va con 0º la componente vertical es nula, con lo cual al hacerse opuesta sale en dirección 180. Si la bola va con 10º ya existe una cierta componente vertical y el rebote que se genera en lugar de ser de 180º es a 170º que es hacia la izquierda y ligeramente hacia abajo en este caso. Si la bola va con 20º el rebote es a 160º. Si la bola va con 30º el rebote es a 150º y así sucesivamente.
Usar 540º nos permite poder operar con cualquier ángulo entre 0 y 360 obteniendo unos resultados correctos y sin tener que operar con ángulos negativos.
Si la bola choca con la pared superior o inferior, por ejemplo llevando un angulo de avance de 80º genera la simetria en este caso respecto al eje x haciendo la resta angle = 360 - angle; por ejemplo para 80 el angulo de rebote es 280 que es una simetria respecto al eje x. Para 10º el angulo de rebote sería 350º.
Aqui las simetrias serian el efecto rebote: si rebota con pared lateral, simetria con la vertical para lo cual ha de usarse 540, si rebota con pared superior o inferior, simetria con la horizontal para lo cual ha de usarse 360.
La simetria respecto a la vertical se consigue a partir de 360 grados. En cambio respecto a la horizontal se consigue con 180. Pero si usaramos 180 no funcionaria con angulos mayores de 180. En cambio usando 540 que es lo mismo se obtiene el angulo de rebote sin importar si el angulo es superior a 180. Luego aplicando el modulo se transforma a un valor entre 0 y 360 equivalente y asi se continua.
El problema que le veo a esto es que es una forma de rebotar absolutamente matematica, lo cual es muy bonito y muy perfecto, pero ocurre una cosa, que es que al no existir nada de aleatoriedad los movimientos se repiten siempre exactamente igual. Es decir, en cada ejecución todo se repite porque siempre se producen los mismos calculos matematicos. Por ejemplo si el angulo de partida es 0 lo pondríamos en this.ball = new Ball(4, 325, drawingPanelDimension); cambiándolo por this.ball = new Ball(4, 0, drawingPanelDimension); pues la bola rebota simétricamente respecto al eje vertical y como va perfectamente horizontal, rebota perfectamente horizontal y lo que hace es estar continuamente de un lado a otro repitiendo siempre el mismo movimiento. Para que no se repitiera el movimiento tendriamos que introducir un factor de aleatoriedad. Pero bueno todo depende de los objetivos que se quisieran lograr en unos casos puede ser interesante hacerlo matematico y en otros un poco aleatorio.
Si buscamos explicaciones normalmente nos vienen como es lo mas habitual, con el angulo de 90 hacia arriba, pero por lo dicho anteriormente java lo trabaja hacia abajo lo cual nos complica un poco la vision porque tenemos que girarlo todo pero para ver la idea nos vale igual
Aqui vemos como si choca con la pared superior con angulo 60 tiene que salir rebotado con angulo 300. Si choca con la pared lateral con angulo 60 tiene que salir rebotado con angulo 120 etc.