Kod będzie krótki i prosty, więc nasze fajerwerki nie będą wyglądać zbyt wymyślnie ani realistycznie – w rzeczywistości będą bardziej przypominać te, które widzieliście na Geocities dwadzieścia lat temu. Ale i tak jest to dobre ćwiczenie z kodowania.
Główny program [linie 5-31] najpierw deklaruje zmienne, a następnie tworzy tablicę obiektów fajerwerków. Każdy fajerwerk będzie miał swoje własne współrzędne x i y, wiek (czas, jaki upłynął od wybuchu), fazę (lot/wybuch) oraz tablicę iskier.
Każda iskra z kolei ma swoją własną prędkość poziomą (vx) i pionową (vy), wagę, która określa, jak szybko spada, oraz kolor (określony przez składowe: czerwoną, zieloną i niebieską).
W [31] uruchamiamy główną funkcję animacji – explode [40-75].
Ta funkcja aktualizuje i rysuje każdą iskrę każdego fajerwerku.
[44-62] to faza wybuchu. W tej fazie każda iskra ma ślad złożony z 10 prostokątów. Obliczamy pozycję każdego prostokąta [45-48] na podstawie współrzędnych fajerwerku, prędkości iskry, „wieku” wybuchu i indeksu prostokąta. Nie użyłem żadnych wzorów balistycznych, zamiast tego metodą prób i błędów wymyśliłem to dziwactwo [48].
[49-52] oblicza kolor każdego prostokąta, biorąc pod uwagę współczynnik zanikania, który wynika z „wieku” wybuchu – im starszy wybuch, tym ciemniejszy kolor.
[53-56] rysuje prostokąt.
W [60-61] istnieje 5% szansy na zresetowanie fajerwerku, jeśli wybuch trwa dłużej niż 100 klatek.
Funkcja resetująca [33-37] umieszcza fajerwerk z powrotem w losowym miejscu na dole ekranu i faza „lotu” rozpoczyna się od nowa.
W tej fazie [64-71] fajerwerk porusza się w górę ekranu [64] i rysowany jest niezwykle prymitywny ogon iskier [65-69].

Istnieje szansa .001, że fajerwerk wybuchnie (zmieni się jego faza) w danej klatce [71]. Wybuchnie na pewno, gdy współrzędna y osiągnie 200.
Miłej zabawy!
| <html> |
| <body style='background-color:black'> |
| <canvas id='myCanvas' width='800' height='800'></canvas> |
| <script> |
| const max_fireworks = 5, |
| max_sparks = 50; |
| let canvas = document.getElementById('myCanvas'); |
| let context = canvas.getContext('2d'); |
| let fireworks = []; |
| |
| for (let i = 0; i < max_fireworks; i++) { |
| let firework = { |
| sparks: [] |
| }; |
| for (let n = 0; n < max_sparks; n++) { |
| let spark = { |
| vx: Math.random() * 5 + .5, |
| vy: Math.random() * 5 + .5, |
| weight: Math.random() * .3 + .03, |
| red: Math.floor(Math.random() * 2), |
| green: Math.floor(Math.random() * 2), |
| blue: Math.floor(Math.random() * 2) |
| }; |
| if (Math.random() > .5) spark.vx = -spark.vx; |
| if (Math.random() > .5) spark.vy = -spark.vy; |
| firework.sparks.push(spark); |
| } |
| fireworks.push(firework); |
| resetFirework(firework); |
| } |
| window.requestAnimationFrame(explode); |
| |
| function resetFirework(firework) { |
| firework.x = Math.floor(Math.random() * canvas.width); |
| firework.y = canvas.height; |
| firework.age = 0; |
| firework.phase = 'fly'; |
| } |
| |
| function explode() { |
| context.clearRect(0, 0, canvas.width, canvas.height); |
| fireworks.forEach((firework,index) => { |
| if (firework.phase == 'explode') { |
| firework.sparks.forEach((spark) => { |
| for (let i = 0; i < 10; i++) { |
| let trailAge = firework.age + i; |
| let x = firework.x + spark.vx * trailAge; |
| let y = firework.y + spark.vy * trailAge + spark.weight * trailAge * spark.weight * trailAge; |
| let fade = i * 20 - firework.age * 2; |
| let r = Math.floor(spark.red * fade); |
| let g = Math.floor(spark.green * fade); |
| let b = Math.floor(spark.blue * fade); |
| context.beginPath(); |
| context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',1)'; |
| context.rect(x, y, 4, 4); |
| context.fill(); |
| } |
| }); |
| firework.age++; |
| if (firework.age > 100 || Math.random() < .05) { |
| resetFirework(firework); |
| } |
| } else { |
| firework.y = firework.y - 10; |
| for (let spark = 0; spark < 15; spark++) { |
| context.beginPath(); |
| context.fillStyle = 'rgba(' + index * 50 + ',' + spark * 17 + ',0,1)'; |
| context.rect(firework.x + Math.random() * spark - spark / 2, firework.y + spark * 4, 4, 4); |
| context.fill(); |
| } |
| if (Math.random() < .001 || firework.y < 200) firework.phase = 'explode'; |
| } |
| }); |
| window.requestAnimationFrame(explode); |
| } |
| </script> |
| </body> |
| </html> |