代码之家  ›  专栏  ›  技术社区  ›  dev101

原始粒子系统-javascript中的二维粒子交互

  •  0
  • dev101  · 技术社区  · 6 年前

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

    我发表这篇文章只是为了保存一个新成员上周在这里发表的有趣的问题,他后来自愿自己删除了这个问题;即使问题在发表后的几个小时内收到了几张赞成票和几颗星。

    链接到原始/现在删除的问题: https://stackoverflow.com/questions/54478107/2d-particle-interactions

    我不是这个领域的专家,现在有点感兴趣,但是我足够聪明,可以离线保存所有代码和链接,以便以后使用;)

    最初的问题-重建


    问题

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

    PPS Pseudo Code

    在给定设置下:

    pps__=___R__=__5,__=__180_”,__=__17_,V__=__0.67__

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

    PPS Generations

    如以下视频所示:

    How life emerges from a simple particle motion law

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

    “你能发布代码吗?”

    “我们把所有需要的东西都写进科学报告的纸上,这就是 开放存取。没有别的了。我们曾经压缩了 完全运行的模型变成了一个tweet。那时候 tweets有140个字符。这个模型非常简单,而且非常短。”

    指本问题开头包含的伪代码。

    问题

    重要提示:此处不复制原始作者的代码工作

    我如何才能使这个工作,如图所示?


    1 回复  |  直到 6 年前
        1
  •  0
  •   dev101    6 年前

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

    1. 由用户 北美设计 @吉图布

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

    Google Drive的旧/原始版本:

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

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

    我只会在这里作为一个片段发布他的旧的更简单的代码版本。 请访问他的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. 由用户 埃尔格姆 @吉图布

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