原始粒子系统 - JavaScript 中的二维粒子相互作用

Primordial Particle System - 2D Particle Interaction in JavaScript

这只是我的复活尝试。在下面阅读更多内容。

我发布这个只是为了保留上周一位新成员在这里发布的一个有趣的问题,后来他自己主动删除了这个问题;即使问题在发布后的几个小时内也收到了一些赞成票和星星。

Link 原/现删问题:

我不是这方面的专家,目前有点兴趣,但是,我足够聪明,将所有代码和链接保存为离线;)

原题-重构


问题

我想模拟和可视化受以下因素支配的粒子相互作用:[ image source ]

使用给定的设置:

PPS = 〈r = 5, α = 180°, β = 17°, v = 0.67〉

有效地复制了以下观察结果:[ image source ]

如下视频所示:

How life emerges from a simple particle motion law

但是创作者并没有像他们所说的那样提供源代码:

"CAN YOU PUBLISH THE CODE PLEASE?"

"We put everything needed into the Scientific Reports paper, which is open-access. There is not more to it. We once compressed the code of the fully running model into a tweet. This was in those days when tweets had 140 characters. The model is super-simple and super-short."

参考本题开头的伪代码

问题

重要说明:此处未复制原作者的代码作品

我怎样才能使它如图所示工作?


JavaScript 中已经有几个针对 PPS 系统的解决方案/工作代码示例:

  1. 用户 nagualdesign @ github

https://github.com/nagualdesign/Primordial-Particle-System

旧/原始版本@Google驱动器:

https://drive.google.com/file/d/1eX_cczNM4qfDue6j83f8T4gG4ecjSV-p

https://drive.google.com/file/d/1KoJf753p3HXPHwP4N2lW9cWLXgusTP72

我只会 post 在这里作为他较旧的更简单代码版本的片段。 请访问他的 GitHub 页面以获取最新版本。

// author: user "nagualdesign" @ github
// github repository: https://github.com/nagualdesign/Primordial-Particle-System
// For more information visit: https://www.youtube.com/watch?v=makaJpLvbow
// This video focuses primarily on specific values of alpha, beta, v and r
// It goes on to show the effects of altering the values of alpha and beta
// To replicate the video it is necessary to tune the density of particles
// Density depends on the screen size, as well as particle size and number
// You can also increase/decrease density by zooming in/out and refreshing

// Global variables:
var a=180; // Alpha in degrees
var b=17; // Beta in degrees
var v=0.67; // Speed of particles
var r=5.0; // Radius of neighbourhood

// Convert to radians!
a=(a/180)*Math.PI;
b=(b/180)*Math.PI;

var canvas, context; // HTML canvas
var t=40; // Time interval in milliseconds
var s=5; // Size/scale of particles
var n=1200; // Number of particles
var p=new Array(n); // Particles

function init() {
 // Set up canvas:
 canvas=document.getElementById("canvas");
 canvas.width=window.innerWidth;
 canvas.height=window.innerHeight;
 context=canvas.getContext("2d");
 for (i=0; i<n; i++) { // Randomize position and orientation of particles:
  p[i]=new Array(4); // Each particle has 4 variables
  p[i][0]=Math.random()*window.innerWidth; // Set random x coordinate
  p[i][1]=Math.random()*window.innerHeight; // Set random y coordinate
  p[i][2]=Math.random()*2*Math.PI; // Set random orientation
 }
}

function draw() {
 context.clearRect(0,0,canvas.width,canvas.height); // Clear canvas
 for (i=0; i<n; i++) { // For each particle:
  // Set fill colour based on number of neighbours:
  let fc='#00C200'; // Green
  if (p[i][3]>35) fc='#F8E302'; // Yellow
  else if (p[i][3]>16) fc='#0064FF'; // Blue
  else if (p[i][3]>15) fc='#FF0792'; // Magenta
  else if (p[i][3]>12) fc='#A4714B'; // Brown
  // Draw particle:
  context.beginPath();
  context.arc(p[i][0],p[i][1],s,0,2*Math.PI);
  context.fillStyle=fc;
  context.fill();
 }
}

function scope(ang) { // Ensure angles are between 0 and 2*pi radians!
 while (ang>(2*Math.PI)) ang=ang-(2*Math.PI);
 while (ang<0) ang=ang+(2*Math.PI);
 return ang;
}

function loop() {
 for (i=0; i<n; i++) { // For each particle:
 // Count neighbors within radius r:
 let nLeft=0, nRight=0, nTotal=0;
 for (j=0; j<n; j++) if (i!=j) { // Compare every other particle:
 let sX=p[j][0]-p[i][0]; // X axis separation
 let sY=p[j][1]-p[i][1]; // Y axis separation
 let sD=Math.sqrt((sX*sX)+(sY*sY)); // Separation distance
 if (sD<(r*s*2)) { // Distance is within radius r
 nTotal++; // Increase count
 let sA=scope(Math.atan2(sY,sX)); // Separation angle
 if (scope(sA-p[i][2])<Math.PI) nRight++; // Neighbour on right
 else nLeft++; // Neighbour on left
 }
 }
 p[i][3]=nTotal; // Used for colouring particles

 // delta_phi = alpha + beta × N × sign(R - L)
 let deltaPhi=a+(b*nTotal*Math.sign(nRight-nLeft));

 // turn right delta_phi
 p[i][2]+=deltaPhi;
 p[i][2]=scope(p[i][2]); // Keep angles within scope!

 // Move forward v
 p[i][0]+=(v*s*2*Math.cos(p[i][2])); // X coordinate
 p[i][1]+=(v*s*2*Math.sin(p[i][2])); // Y coordinate

 // Wrap screen edges, Pac-Man style!
 if (p[i][0]<(s*-1)) p[i][0]=(canvas.width+s);
 else if (p[i][0]>(canvas.width+s)) p[i][0]=(s*-1);
 if (p[i][1]<(s*-1)) p[i][1]=(canvas.height+s);
 else if (p[i][1]>(canvas.height+s)) p[i][1]=(s*-1);
 }
 draw(); // Update canvas
}

function run() {
 init();
 run=setInterval(loop,t);
}
<body style="margin:0; background:#000; overflow:hidden;" onLoad="run();">
<canvas id="canvas" onclick="window.clearTimeout(run)"></canvas>
</body>

  1. 用户 elggem @ github

https://github.com/elggem/js-primordialparticles demo