Powitajmy Nowy Rok fajerwerkami!



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='myCanvaswidth='800height='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 = 0i < max_fireworksi++) {
  let firework = {
    sparks: []
  };
  for (let n = 0n < max_sparksn++) {
    let spark = {
      vxMath.random() * 5 + .5,
      vyMath.random() * 5 + .5,
      weightMath.random() * .3 + .03,
      redMath.floor(Math.random() * 2),
      greenMath.floor(Math.random() * 2),
      blueMath.floor(Math.random() * 2)
    };
    if (Math.random() > .5spark.vx = -spark.vx;
    if (Math.random() > .5spark.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(00canvas.widthcanvas.height);
  fireworks.forEach((firework,index) => {
    if (firework.phase == 'explode') {
        firework.sparks.forEach((spark) => {
        for (let i = 0i < 10i++) {
          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(xy44);
          context.fill();
        }
      });
      firework.age++;
      if (firework.age > 100 || Math.random() < .05) {
        resetFirework(firework);
      }
    } else {
      firework.y = firework.y - 10;
      for (let spark = 0spark < 15spark++) {
        context.beginPath();
        context.fillStyle = 'rgba(' + index * 50 + ',' + spark * 17 + ',0,1)';
        context.rect(firework.x + Math.random() * spark - spark / 2firework.y + spark * 444);
        context.fill();
      }
      if (Math.random() < .001 || firework.y < 200firework.phase = 'explode';
    }
  });
  window.requestAnimationFrame(explode);
}
</script>
</body>
</html>