Animowane gwiazdozbiory cząsteczek
No dobra, przestań się gapić na te cholerne kropki i zacznij programować!
Widziałem animacje podobne do powyższej na kilku stronach i spodobała mi się prostota pomysłu, więc napiszmy taki programik - wystarczy nam 42 linie kodu.
Przepis wygląda z grubsza tak:
- kilka tuzinów losowych cząsteczek (particles) odbija się od brzegów Canvas
- obliczamy odległość między każdą parą cząsteczek
- jeżeli odległość jest mniejsza niż ustalony próg, rysujemy między nimi linię
Oto pełen kod, a dokładniejszy opis jest poniżej:
<html> |
<body bgcolor=black> |
<canvas id="myCanvas" width="800" height="600"></canvas> |
<script> |
|
function line(particle, particle2) { |
context.beginPath(); |
context.moveTo(particle.x, particle.y); |
context.lineTo(particle2.x, particle2.y); |
context.stroke(); |
} |
|
function animate() { |
context.clearRect(0, 0, canvas.width, canvas.height); |
for (let i = 0; i < maxParticles; i++) { |
let particle = particles[i]; |
context.fillRect(particle.x - particleSize / 2, particle.y - particleSize / 2, particleSize, particleSize); |
for (let j = i; j < maxParticles; j++) { |
if (i != j) { |
let particle2 = particles[j]; |
let distanceX = Math.abs(particle.x - particle2.x); |
let distanceY = Math.abs(particle.y - particle2.y); |
if (distanceX < threshold && distanceY < threshold) { |
context.lineWidth = ((threshold * 2) - (distanceX + distanceY)) / 50; |
let color = 200 - Math.floor(distanceX + distanceY); |
context.strokeStyle = 'rgb(' + color + ',' + color + ',' + color + ')'; |
line(particle, particle2); |
} |
} |
} |
particle.x = particle.x + particle.vx; |
particle.y = particle.y + particle.vy; |
if (particle.x > canvas.width - particleSize || particle.x < particleSize) |
particle.vx = -particle.vx; |
if (particle.y > canvas.height - particleSize || particle.y < particleSize) |
particle.vy = -particle.vy; |
} |
window.requestAnimationFrame(animate); |
} |
|
let canvas = document.getElementById('myCanvas'); |
let context = canvas.getContext('2d'); |
let particles = []; |
let particleSize = 4; |
let maxParticles = 40; |
let threshold = 100; |
for (let i = 0; i < maxParticles; i++) { |
let particle = { |
x: Math.random() * canvas.width, |
y: Math.random() * canvas.height, |
vx: Math.random(), |
vy: Math.random() |
} |
particles.push(particle); |
} |
context.fillStyle = 'white'; |
animate(); |
|
</script> |
</body> |
</html> |
[1-4] ustawienia HTML
[6-11] funkcja, która rysuje linię między dwiema cząsteczkami
[13-39] główna funkcja animacji:
[14] czyszczenie poprzedniej ramki
[15-37] dla każdej cząsteczki:
[18-27] sprawdź z każdą pozostałą cząsteczką
[19] upewnij się, że nie sprawdzasz cząsteczki samej ze sobą
[21-22] oblicz przybliżoną odległość między cząsteczkami (jako sumę różnic współrzędnych X i Y). Możesz użyć dokładnej odległości [sqrt(distanceX^2+distanceY^2)], ale to tylko zwalnia program, a tak naprawdę różnica nie jest widoczna.
[23] Jeżeli różnica jest mniejsza niż założony próg...
[24] ...szerokość...
[25-26] ...i kolor linii (odcień szarości z równymi wartościami składników RGB (czerwony/zielony/niebieski) zależy od odległości. Ciekawostka: Math.floor jest tylko niezbędne dla iOS - inne platformy obsługują wartości zmiennoprzecinkowe.
[31-32] Cząsteczka rusza się w obu osiach
[34-36] Odbicie od krawędzi
[41-46] Ustawienia Canvas i parametrów.
[47-54] Inicjalizacja cząsteczek z losowymi współrzędnymi i prędkościami.
[57] Do dzieła!
Eksperymentuj z różnymi parametrami, na przykład maxParticles = 100 i threshold = 40.
Inne samouczki:
Fraktale - 25 linii JavaScript
Złudzenie optyczne - 18 linii
Sinus scroll - 30 linii
Gra "Angry Chickens"
Walentynkowe serca
Animowane krzywe kwadratowe - 40 linii
Eksperyment z enginem fizyki
Rozbijanie muru kulą - 14 linii Python/Blender 3d
Efekt domino - 10 linii Python/Blender 3d
English version of this page