Let it run! Eventually life seems to emerge. Press mouse to change attraction rules. Reload to change colors. Enjoy!
xxxxxxxxxx
/*
A p5.js version of Terry Soule's Particle Life by Programming Chaos:
https://youtu.be/xiUpAeos168?feature=shared
This version by Juan Carlos Ponce Campuzano
https://www.dynamicmath.xyz
7/Jul/2024
Improved performance with 1000 particles and fullscreen
14/Jul/2024
processing.js version here:
https://openprocessing.org/sketch/2312175
Three.js version here:
https://www.dynamicmath.xyz/threejs/particle-life/
Processing source code here:
https://github.com/jcponce/jcponce.github.io/tree/master/sketches/particle-life/particle-life
🎵 Music: Spenta Mainyu by Jesse Gallagher
https://www.youtube.com/channel/UCD5hjK3sDzk2W-jw9roHuVw
Note: You may have to reload the page again to start the music.
A first attempt:
https://openprocessing.org/sketch/2265246
*/
let music;
let numTypes;
let colorStep;
let numParticles = 1000;
let swarm = [];
let forces;
let minDistances;
let radii;
function preload(){
music = createAudio("https://topologia-general.github.io/sketches/audio/jesse-gallagher/spenta-mainyu-jesse-gallagher.mp3");
}
/*
A p5.js version of Particle Life by Programming Chaos:
https://www.youtube.com/watch?v=xiUpAeos168&ab_channel=ProgrammingChaos
This version by Juan Carlos Ponce Campuzano
https://www.dynamicmath.xyz
14/Jul/2024
*/
function setup() {
createCanvas(windowWidth, windowHeight);
colorMode(HSB, 360, 100, 100, 100);
noStroke();
numTypes = int(random(2,6));
colorStep = 360 / numTypes;
for (let i = 0; i < numParticles; i++) {
swarm.push(new Particle());
}
forces = Array.from({ length: numTypes }, () => new Float32Array(numTypes));
minDistances = Array.from({ length: numTypes }, () => new Float32Array(numTypes));
radii = Array.from({ length: numTypes }, () => new Float32Array(numTypes));
setParameters();
}
function draw() {
background(0);
for (let p of swarm) {
p.update();
p.display();
}
}
function mousePressed(){
setParameters();
}
function setParameters() {
for (let i = 0; i < numTypes; i++) {
for (let j = 0; j < numTypes; j++) {
forces[i][j] = random(0.3, 1.0);
if (random(100) < 50) {
forces[i][j] *= -1;
}
minDistances[i][j] = random(30, 50);
radii[i][j] = random(70, 250);
}
}
}
let K = 0.05;
let friction = 0.85;
class Particle {
constructor() {
let rad = random(100);
let ang = random(TWO_PI);
this.position = createVector(rad * cos(ang) + width/2, rad * sin(ang)+height/2);
this.velocity = createVector(0, 0);
this.type = int(random(numTypes));
this.tempVector = createVector(0, 0);
}
update() {
let direction = this.tempVector;
let totalForce = createVector(0, 0);
let acceleration = createVector(0, 0);
let dis;
for (let i = 0; i < swarm.length; i++) {
let p = swarm[i];
if (p !== this) {
direction.set(p.position.x, p.position.y);
direction.sub(this.position);
if (direction.x > 0.5 * width) direction.x -= width;
if (direction.x < -0.5 * width) direction.x += width;
if (direction.y > 0.5 * height) direction.y -= height;
if (direction.y < -0.5 * height) direction.y += height;
dis = direction.mag();
direction.normalize();
if (dis < minDistances[this.type][p.type]) {
let force = direction.copy();
force.mult(abs(forces[this.type][p.type]) * -3);
force.mult(map(dis, 0, minDistances[this.type][p.type], 1, 0));
force.mult(K);
totalForce.add(force);
}
if (dis < radii[this.type][p.type]) {
let force = direction.copy();
force.mult(forces[this.type][p.type]);
force.mult(map(dis, 0, radii[this.type][p.type], 1, 0));
force.mult(K);
totalForce.add(force);
}
}
}
acceleration.add(totalForce);
this.velocity.add(acceleration);
this.position.add(this.velocity);
this.position.x = (this.position.x + width) % width;
this.position.y = (this.position.y + height) % height;
this.velocity.mult(friction);
}
display() {
push();
//blendMode(ADD);
fill(this.type * colorStep, 80, 100, 90);
circle(this.position.x, this.position.y, 7);
pop();
}
}