Un casse-briques rétro à l'ambiance néon. Bougez la souris pour déplacer la raquette, cliquez pour lancer la balle. Certaines briques libèrent des power-ups: balle supplémentaire ou raquette élargie.
Bougez la souris pour viser, cliquez pour lancer la balle.
La raquette suit la souris à l'horizontale et le curseur est masqué au-dessus du cadre. Un clic lance la balle; sur écran tactile, un doigt fait les deux à la fois. On part avec trois vies et une grille de 45 briques réparties sur 5 rangées de 9.
Les briques du haut valent 50 points, celles du bas 10: la rangée la plus payante est aussi la plus difficile à atteindre. Environ une brique détruite sur cinq laisse tomber un power-up. Le jaune marqué W élargit la raquette de 70 % pendant huit secondes, le turquoise marqué +B ajoute une balle en jeu. Quand la grille est vide, le niveau suivant se dessine et la balle repart plus vite.
Tout le contact passe par une seule fonction, circleRectCollision. Je ramène le
centre de la balle sur le point le plus proche du rectangle avec deux bornages successifs, puis je
compare la distance au carré au rayon au carré. Aucune racine carrée, et le même test sert pour la
raquette, pour les briques et pour la capture des power-ups.
Le rebond sur la raquette n'est pas une réflexion physique, et c'est délibéré. Je calcule
hitPos, la position du contact normalisée entre -1 et 1 par rapport au centre de la
raquette, et j'en dérive directement un angle de sortie qui balaie soixante degrés de chaque côté de
la verticale. Frapper avec le bord envoie la balle en biais, frapper au centre la renvoie droit.
C'est exactement ce qui rend la raquette pilotable au lieu d'être subie.
La vitesse est recalculée à chaque contact avec la raquette, en gardant le plus grand entre la
vitesse actuelle et BASE_BALL_SPEED augmenté de 25 px/s par niveau franchi. Comme les
rebonds sur les murs et sur les briques ne font qu'inverser un signe, la norme reste constante entre
deux touches de raquette. Effet de bord que j'ai remarqué en relisant: launchBalls
utilise la vitesse de base sans le bonus de niveau, donc au niveau quatre la balle n'atteint sa
vitesse annoncée qu'après avoir touché la raquette une première fois.
Sur les briques, l'axe du rebond est choisi en comparant le chevauchement horizontal et le
chevauchement vertical: le plus petit des deux l'emporte et la composante correspondante est
inversée. handleBrickCollision s'arrête à la première brique touchée par image et par
balle, avec un break assumé.
L'état du jeu tient dans une seule chaîne de caractères, state, qui vaut
ready, playing, lost ou win. Tant qu'on est en
attente, la balle est recollée au centre de la raquette à chaque image. Le voile de message est en
pointer-events: none, donc les clics le traversent et atteignent le canvas en dessous.
Le néon, lui, se résume à shadowColor et shadowBlur posés avant chaque
remplissage et remis à zéro juste après, sur un canvas redimensionné au rapport de pixels de
l'écran, plafonné à deux.
Première leçon: le contrôle vient de l'angle imposé par la raquette, pas de la simulation. Un rebond physiquement juste rendrait le jeu injouable, parce que le joueur n'aurait aucune prise sur la trajectoire. C'est un des cas où s'éloigner de la physique est la bonne réponse.
Deuxième leçon, un défaut que je laisse visible parce qu'il est instructif: resize
rappelle layoutBricks, donc redimensionner la fenêtre en pleine partie fait réapparaître
toutes les briques détruites pendant que le score, lui, reste acquis. La géométrie des briques et
leur état de destruction vivent dans le même tableau, et c'est ça le vrai problème. Il faudrait
recalculer les positions au redimensionnement et laisser survivre le drapeau de destruction. J'ai
aussi laissé un paramètre fullReset sur resetGame qui n'est jamais lu.