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-color: black; |
} |
</style> |
<body> |
<canvas id="myCanvas" width="800" height="600"></canvas> |
<script> |
const time = 255 * 2; |
let x = [], y = [], speedX = [], speedY = []; |
let red, green, blue, randomRed, randomGreen, randomBlue, counter, fade; |
|
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 = 0; n < 5; n++) { |
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(0, 0, canvas.width, canvas.height); |
|
fade = Math.abs(time / 2 - counter); |
for (let n = 0; n < 64; n++) { |
green = n * 4 + 1; |
green = Math.max(green - fade, 0); |
green = green * randomGreen; |
blue = 255 - n * 4; |
blue = Math.max(blue - fade, 0); |
blue = blue * randomBlue; |
red = Math.max(randomRed * 256 - fade, 0); |
context.strokeStyle = 'rgba(' + red + ',' + green + ',' + blue + ',1)'; |
|
context.beginPath(); |
context.moveTo(x[0], y[0]); |
context.quadraticCurveTo(x[1], y[1], x[2] + n * 5, y[2] + n * 5); |
context.quadraticCurveTo(x[3], y[3], x[4] + n * 5, y[4] + n * n); |
context.quadraticCurveTo(x[1], y[1], x[0], y[0]); |
context.stroke(); |
} |
counter++; |
if (counter == time) |
reset(); |
|
for (let n = 0; n < 5; n++) { |
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