Javascript: жизнь частиц
Такая небольшая модель не без физики, в чём-то "Жизнь" Конвэя напоминает, но другая :)
Суть дела довольно простая - есть частицы, заданные положением на холсте, радиусом, скоростью, направлением движения и цветом.
Если расстояние между двумя частицами одного цвета становится меньше заданного, они начинают расти, визуально сцепляются линией и замедляют скорость разбегания.
Также частицы меньшего радиуса могут "захватываться" большими, перекрашиваясь в их цвет.
Изменение коэффициентов, которые хорошо видны из листинга и закомментированы, может существенно изменить и наблюдаемую картинку, конечно :)
Ну и сам скрипт в работе + исходник - под катом, нужны только JS и канва, без внешних библиотек. Исходник можно сохранить как файл типа .html
и выполнить в любом браузере. Листинг приводится без стандартных тегов оформления файла HTML.
<style> .circlesCanvas { margin:0; padding:0; border: 0; background:#000000; } </style> <div align="center"> <canvas id="circlesCanvas" class="circlesCanvas" width="600" height="600"></canvas> </div> <script> var canvas = document.getElementById('circlesCanvas'); var ctx = canvas.getContext('2d'); ctx.setLineDash([2,1]); //стиль линий ctx.globalCompositeOperation = 'lighter'; //складывать цвета перекрывающихся путей var pieces = []; var piecesNum = 100; //количество частиц var w = canvas.width; var h = canvas.height; var colors = ['#ff0000','#0000ff','#00ff00','#ffff00','#ff00ff']; //цвета частиц var concatLength = 50; //расстояние для сцепления var velocityFactor = 0.35; //коэффициент уменьшения скорости разлетания для сцеплённых, интверал ]0,1[, //чем ближе к нулю, тем сильныее столкновение замедляет сцеплённые частицы function randomPiece () { this.x = Math.round ( Math.random() * w); this.y = Math.round ( Math.random() * h); this.rad = 1 + Math.floor ( Math.random() * 2); this.rgba = colors[ Math.floor(Math.random()*colors.length) ]; this.vx = Math.round( Math.random() * 3) - 1.5; this.vy = Math.round( Math.random() * 3) - 1.5; } function draw(){ ctx.clearRect(0, 0, w, h); for (var i = 0; i < piecesNum; i++) { var temp = pieces[i]; var factor = 1; for (var j = 0; j < piecesNum; j++) if ( i != j ) { var temp2 = pieces[j]; if (temp.rgba != temp2.rgba && inside (temp, temp2, factor)) { //поглощение pieces[i].rgba = temp.rgba = temp2.rgba; } if (temp.rgba == temp2.rgba && dist (temp, temp2) < concatLength) { //столкновение ctx.strokeStyle = temp.rgba; ctx.beginPath(); ctx.moveTo (temp.x, temp.y); ctx.lineTo (temp2.x, temp2.y); ctx.stroke(); factor++; } } ctx.fillStyle = temp.rgba; ctx.strokeStyle = temp.rgba; //У сцеплённых больше радиус... ctx.beginPath(); ctx.arc (temp.x, temp.y, temp.rad*factor, 0, Math.PI*2, true); ctx.fill(); ctx.closePath(); ctx.beginPath(); ctx.arc(temp.x, temp.y, (temp.rad+5)*factor, 0, Math.PI*2, true); ctx.stroke(); ctx.closePath(); //...и ниже скорость разлетания: temp.x += temp.vx/(factor*velocityFactor); temp.y += temp.vy/(factor*velocityFactor); if (temp.x > w) temp.x = 0; if (temp.x < 0) temp.x = w; if (temp.y > h) temp.y = 0; if (temp.y < 0) temp.y = h; } } function dist (p1,p2) { //расстояние между частицами return Math.sqrt ( Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2) ); } function inside (a,b,factor) { //поглощает ли b частицу a ? return (a.x > b.x-b.rad*factor && a.x < b.x+b.rad*factor && a.y > b.y-b.rad*factor && a.y < b.y+b.rad*factor && a.rad < b.rad); } window.requestAnimFrame = (function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 200); }; })(); (function init () { for (var i = 0; i < piecesNum; i++){ pieces.push(new randomPiece()); } })(); (function loop() { draw(); requestAnimFrame(loop); })(); </script> <noscript>You need Javascript to run it</noscript>
Больше крупных "молекул" будет образовываться, если учитывать при столкновении попадание частицы не только в "ядро" другой частицы, но и в её "электронную орбиталь":
function inside (a,b,factor) { //поглощает ли b частицу a ? return (a.x > b.x-(b.rad+5)*factor && a.x < b.x+(b.rad+5)*factor && a.y > b.y-(b.rad+5)*factor && a.y < b.y+(b.rad+5)*factor && a.rad < b.rad); }
Интересная и быстрая картинка при настройках piecesNum = 500 и velocityFactor = 0.05
03.01.2019, 12:50 [2000 просмотров]