Animowane krzywe kwadratowe


W mojej niekończącej się eksploracji pogranicza kodu i poezji natknąłem się na ciemne miejsce, gdzie tajemnicze kształty na krótką chwilę ukazują swe urzekające piękno, by zniknąć na powrót na resztę wieczności w ciemnej cyber czeluści.

Innymi słowy, oto prosty programik, który animuje krzywe kwadratowe na HTML5 Canvas.

Wreszcie coś, co wygląda naprawdę spoko, a jest łatwe to napisania i nie wymaga matematyki trudniejszej niż to, czego nauczyliście się o czterech podstawowych działaniach w trzeciej klasie podstawówki - bez trygonometrii, liczb złożonych ani bezpośrednich operacji na bitmapach.

Spójrzmy od razu na kod:

<html>
<style>
body {
  background-colorblack;
}
</style>
<body>
<canvas id="myCanvaswidth="800height="600"></canvas>
<script>
const time = 255 * 2;
let x = [], y = [], speedX = [], speedY = [];
let redgreenbluerandomRedrandomGreenrandomBluecounterfade;
 
let canvas = document.getElementById('myCanvas');
let context = canvas.getContext('2d');
 
function reset() {
  counter = 0;
  randomRed = Math.random();
  randomGreen = Math.random();
  randomBlue = Math.random();
 
  for (let n = 0n < 5n++) {
    x[n] = Math.floor(Math.random() * canvas.width);
    y[n] = Math.floor(Math.random() * canvas.height);
    speedX[n] = -2 + Math.random() * 4;
    speedY[n] = -2 + Math.random() * 4;
  }
}
 
function animate() {
  context.clearRect(00canvas.widthcanvas.height);
 
  fade = Math.abs(time / 2 - counter);
  for (let n = 0n < 64n++) {
    green = n * 4 + 1;
    green = Math.max(green - fade0);
    green = green * randomGreen;
    blue = 255 - n * 4;
    blue = Math.max(blue - fade0);
    blue = blue * randomBlue;
    red = Math.max(randomRed * 256 - fade0);
    context.strokeStyle = 'rgba(' + red + ',' + green + ',' + blue + ',1)';
 
    context.beginPath();
    context.moveTo(x[0], y[0]);
    context.quadraticCurveTo(x[1], y[1], x[2] + n * 5y[2] + n * 5);
    context.quadraticCurveTo(x[3], y[3], x[4] + n * 5y[4] + n * n);
    context.quadraticCurveTo(x[1], y[1], x[0], y[0]);
    context.stroke();
  }
  counter++;
  if (counter == time)
    reset();
 
  for (let n = 0n < 5n++) {
    x[n] = x[n] + speedX[n];
    y[n] = y[n] + speedY[n];
  }
  window.requestAnimationFrame(animate);
 
reset();
window.requestAnimationFrame(animate);
</script>
</body>
</html>



Zarys:

W skrócie, mamy 5 punktów na ekranie. Rysujemy między nimi 3 krzywe kwadratowe. Dla każdej z tych krzywych rysujemy 63 dalsze krzywe, za każdym razem nieco przesuwając punkty i lekko zmieniając kolor.
W każdej ramce animacji przesuwamy nasze 5 punktów. Po około 500 ramkach zaczynamy nowy zestaw krzywych: losujemy nowe współrzędne punktów, ich prędkości i kolor krzywych.
Współczynnik "fade" (zanikanie, zaciemnienie) zmniejsza się z 255 do 0 w pierwszej połowie zestawu (rozjaśnianie), a potem zwiększa się w drugiej połowie (zaciemnianie).

Oto jak działają krzywe kwadratowe:



By narysować tę białą krzywą, najpierw przesuwamy pióro do punktu 0 (poczatek), a potem wykonujemy quadraticCurveTo(punkt 1, punkt 2)
Punkt 2 jest końcem. Punkt 1 jest punktem kontrolnym - określa on kształt (wygięcie) krzywej między początkiem a końcem. Czerwone linie pokazują tylko, gdzie jest punkt kontrolny.
W naszym programie dodajemy drugą krzywą na końcu pierwszej (niebieska na tym rysunku):



I trzecią (zielona), z powrotem do pierwszej. Tym razem nie pokazują czerwonych linii. W naszym ostatecznym programie wszystkie 3 krzywe (biała, niebieska i zielona) będą jednego koloru. Trzy kolory zostały tu użyte, by pomóc wam zrozumieć mechanizm kształtu.



Spójrzmy, co dzieje się, jeżeli dla każdej z tych krzywych narysujemy podobne, przesuwając lekko niektóre punkty:



Zatem same krzywe są stosunkowo nieskomplikowane. To, co czyni je ciekawymi i powoduje złudzenie trójwymiarowości (podobne do żagli) to klonowanie ich z przesunięciem.

Teraz wiecie, jak stworzyć ten kształt. Pozostaje tylko przesunięcie kolorów i animacja pięciu punktów...


Szczegóły:

Linie [1-9] odpalają HTML5 Canvas
[10] czas - przez ile ramek wyświetlamy jeden zestaw krzywych
[11] współrzędne i prędkości punktów
[12-16] kolory i inne zmienne, ustawienia HTML
[17-29] funkcja "reset" tworzy nowy zestaw krzywych poprzez wylosowanie dla nich nowych parametrów.
[31-61] To jest fragment kodu, który faktycznie odwala całą robotę:
[32] czyszczenie poprzedniej ramki. Usunięcie tej linii powoduje ciekawy efekt - spróbujcie!
[34] obliczenie aktualnego współczynnika zanikania
[35] pętla, która rysuje 64 krzywe
[36] zielony składnik koloru krzywej RGB (Red/Green/Blue) jest proporcjonalny do numeru krzywej (n)
[37] odejmujemy współczynnik zanikania. Jeżeli wynik jest ujemny, użyj 0
[38] uwzględniamy współczynnik losowy dla składnika zielonego dla danego zestawu
[39-41] niebieski składnik jest analogiczny do zielonego, z tym, że proporcja jest odwrócona
[42] czerwony składnik nie zależy od numeru linii
[43] ustal kolor krzywej obliczony w liniach [36-42]
[45] początek krzywej
[46] przejdź do punktu 0
[47] rysuj pierwszą krzywą - do punktu 2
[48] rysuj drugą krzywą - do punktu 4
[49] rysuj trzecią krzywą - z powrotem do punktu 0
[50] zakończ krzywą
[52] zwiększ licznik klatek
[53-54] jeżeli licznik osiągnął limit, zacznij nowy zestaw krzywych
[56-59] przesuń współrzędne każdego punktu o jego prędkości (w osiach x i y)
[60-61] to główny program - tworzy on jedynie pierwszy zestaw i uruchamia animację

Inne samouczki:

Fraktale - 25 linii JavaScript

Złudzenie optyczne - 18 linii

Sinus scroll - 30 linii

Gra "Angry Chickens"

Eksperyment z enginem fizyki


Rozbiajanie muru kulą - 14 linii Python/Blender 3d


Efekt domino - 10 linii Python/Blender 3d


English version of this page