БлогNot. Javascript: жизнь частиц

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
Интересная и быстрая картинка при настройках piecesNum = 500 и velocityFactor = 0.05

03.01.2019, 12:50 [1943 просмотра]


теги: javascript графика random

К этой статье пока нет комментариев, Ваш будет первым