Ünnepeljünk tűzijátékkal!



A kódot röviden és egyszerűen tartjuk, így a tűzijátékaink nem lesznek túl flancosak vagy valósághűek - valójában inkább azokhoz fognak hasonlítani, amiket húsz évvel ezelőtt a Geocities-en látott. De azért ez még mindig egy jó kódolási gyakorlat.

A fő program [5-31. sor] először deklarálja a változókat, majd létrehoz egy tömböt a tűzijáték objektumokból. Minden tűzijátéknak saját x és y koordinátája, kora (a robbanás óta eltelt idő), fázisa (repülés/robbanás) és egy szikrákból álló tömbje lesz.
Minden szikrának van saját vízszintes (vx) és függőleges (vy) sebessége, súlya, amely meghatározza, milyen gyorsan esik, és egy színe (amelyet a vörös, zöld és kék komponensek határoznak meg).

A [31]-es sorban indítjuk el a fő animációs függvényt - explode [40-75].
Ez a függvény frissíti és rajzolja ki az egyes tűzijátékok minden szikráját.
A [44-62] a robbanási fázis. Ebben a fázisban minden szikrának van egy 10 téglalapból álló csóvája. Minden téglalap pozícióját [45-48] a tűzijáték koordinátái, a szikra sebessége, a robbanás 'kora' és a téglalap indexe alapján számoljuk ki. Nem használtam semmilyen ballisztikai képletet, helyette ezt a furcsaságot [48] találtam ki próbálgatással.
A [49-52] kiszámítja az egyes téglalapok színét, figyelembe véve a halványulási tényezőt, amely a robbanás 'korából' származik - minél régebbi a robbanás, annál sötétebb a szín.
Az [53-56] kirajzolja a téglalapot.
A [60-61]-ben 5% esély van a tűzijáték visszaállítására, ha a robbanás régebbi, mint 100 képkocka.
A visszaállító függvény [33-37] a tűzijátékot egy véletlenszerű helyre teszi a képernyő alján, és a 'repülés' fázis újra kezdődik.
Ebben a fázisban [64-71] a tűzijáték felfelé mozog a képernyőn [64], és egy rendkívül kezdetleges szikracsóva kerül kirajzolásra [65-69].


Van 0,001 esély arra, hogy a tűzijáték felrobban (a fázisa megváltozik) egy adott képkockán [71]. Biztosan felrobban, amint az y koordináta eléri a 200-at.

Jó szórakozást!

<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>



Egy újabb JavaScript oktatóanyag: Buborékrendezés vizualizáció