xxxxxxxxxx
341
/** ParticleLife by Lukalot & Heavpoot
Controls:
SPACE - Change particle placing state
LEFT CLICK - Place a particle
OPTION - Use auto place
NAVIGATE - Arrows or WASD
ZOOM IN/OUT - Z/X or +/-
T - Toggle tracking mode
C - Reset cameraz
Q - Clear canvas of all particles
N - Create new canvas with same rule
R - Re-randomize rule
P - Print rule values (Load at line 185)
**/
function setup() {
createCanvas(1500, 1000);
if (randGen) {
for (var i = 0; i < genDensity; i++) {
particles.push(new Particle(createVector((Math.random(-(width / 2)) - 0.5) * width, (Math.random() - 0.5) * height), Math.floor(Math.random() * 4), createVector(0, 0)));
}
}
translate(width / 2, height / 2);
background(backgroundCol[0], backgroundCol[1], backgroundCol[2]);
if (zoom >= 1) {
drawGrid();
}
}
//CHANGE THESE
var speedMultInt = 1;
var randGen = true;
var genDensity = 200;
var trackingMode = false;
//Rule variables
var psize = 10;
var strRepPercent = 100;
var interactionLimit = 100;
var fric = 0.4;
//Graphics variables
var gridSpacing = 40;
var backgroundCol = [20, 20, 30]; //Dark Preset (Uncommented for dark)
//backgroundCol = [245, 245, 255]; //Light preset (Uncommented for light)
var partColors = [
[200, 50, 50], // state 0
[50, 200, 50], // state 1
[50, 50, 200], // state 2
[200, 50, 200], // state 3
]
var focus = false;
var particles = [];
//Camera variables
{
var camX = 0;
var camY = 0;
var camVel = 1.5;
var maxCamSpeed = 18;
var zoom = 1;
}
var typeToPlace = 0;
var camClear = false;
function mouseClicked() {
if (mouseButton === LEFT && focus) {
particles.push(new Particle(createVector(((mouseX - camX) - width / 2) / zoom, ((mouseY - camY) - height / 2) / zoom), typeToPlace, createVector(0, 0)));
}
focus = true;
}
function keyPressed() {
if (key === " ") {
typeToPlace = (typeToPlace + 1) % 4;
console.log("Cycled placing type to " + typeToPlace);
} else if (key === "t") {
trackingMode = !trackingMode;
console.log("Toggled tracking to " + trackingMode);
} else if (key === "c") {
camX = 0;
camY = 0;
zoom = 1;
camClear = true;
console.log("Reset camera to default position");
} else if (key === "q") {
particles = [];
console.log("Cleared canvas");
camClear = true;
} else if (key === "f") {
var longest = 0;
var longestID = 0;
for (var i = 0; i < particles.length+1; i++) {
if (dist(particles[constrain(i, 0, particles.length-1)].pos.x, particles[constrain(i, 0, particles.length-1)].pos.y, camX, camY) > longest) {
longest = dist(particles[constrain(i, 0, particles.length-1)].pos.x, particles[constrain(i, 0, particles.length-1)].pos.y, camX, camY);
longestID = i;
if (i == particles.length) {
camX = particles[longestID].pos.x;
camY = particles[longestID].pos.y;
console.log(particles[longestID].pos.y);
}
}
}
console.log("Jumped to farthest particle");
} else if (key === "n") {
camClear = true;
particles = [];
console.log("Created new canvas with same rule");
if (randGen) {
for (var i = 0; i < genDensity; i++) {
particles.push(new Particle(createVector((Math.random(-(width / 2)) - 0.5) * width, (Math.random() - 0.5) * height), Math.floor(Math.random() * 4), createVector(0, 0)));
}
}
} else if (key === "r") {
interaction[[0, 0]] = Math.random() - 0.5;
interaction[[0, 1]] = Math.random() - 0.5;
interaction[[0, 2]] = Math.random() - 0.5;
interaction[[0, 3]] = Math.random() - 0.5;
interaction[[1, 0]] = Math.random() - 0.5;
interaction[[1, 1]] = Math.random() - 0.5;
interaction[[1, 2]] = Math.random() - 0.5;
interaction[[1, 3]] = Math.random() - 0.5;
interaction[[2, 0]] = Math.random() - 0.5;
interaction[[2, 1]] = Math.random() - 0.5;
interaction[[2, 2]] = Math.random() - 0.5;
interaction[[2, 3]] = Math.random() - 0.5;
interaction[[3, 0]] = Math.random() - 0.5;
interaction[[3, 1]] = Math.random() - 0.5;
interaction[[3, 2]] = Math.random() - 0.5;
interaction[[3, 3]] = Math.random() - 0.5;
console.log("Randomized rule");
} else if (key === "p") {
console.log("Printing rule to console...\n-");
console.log("interaction[[0, 0]] = " + interaction[[0, 0]] + ";\ninteraction[[0, 1]] = " + interaction[[0, 1]] + ";\ninteraction[[0, 2]] = " + interaction[[0, 2]] + ";\ninteraction[[0, 3]] = " + interaction[[0, 3]] + ";");
console.log("interaction[[1, 0]] = " + interaction[[1, 0]] + ";\ninteraction[[1, 1]] = " + interaction[[1, 1]] + ";\ninteraction[[1, 2]] = " + interaction[[1, 2]] + ";\ninteraction[[1, 3]] = " + interaction[[1, 3]] + ";");
console.log("interaction[[2, 0]] = " + interaction[[2, 0]] + ";\ninteraction[[2, 1]] = " + interaction[[2, 1]] + ";\ninteraction[[2, 2]] = " + interaction[[2, 2]] + ";\ninteraction[[2, 3]] = " + interaction[[2, 3]] + ";");
console.log("interaction[[3, 0]] = " + interaction[[3, 0]] + ";\ninteraction[[3, 1]] = " + interaction[[3, 1]] + ";\ninteraction[[3, 2]] = " + interaction[[3, 2]] + ";P\ninteraction[[3, 3]] = " + interaction[[3, 3]] + ";");
console.log("psize = " + psize + ";");
console.log("strRepPercent = " + strRepPercent + ";");
console.log("interactionLimit = " + interactionLimit + ";");
console.log("fric = " + fric + ";");
console.log("-");
}
}
function keyReleased() {
if (key === "z" || key === "=") {
console.log("Zoomed in to " + zoom + "x");
} else if (key === "x" || key === "-") {
console.log("Zoomed out to " + zoom + "x");
}
keyIsPressed = false;
}
var Particle = function(pos, type, vel) {
this.pos = pos;
this.ppos = this.pos;
this.type = type;
this.vel = vel;
};
var interaction = [];
interaction[[0, 0]] = Math.random() - 0.5;
interaction[[0, 1]] = Math.random() - 0.5;
interaction[[0, 2]] = Math.random() - 0.5;
interaction[[0, 3]] = Math.random() - 0.5;
interaction[[1, 0]] = Math.random() - 0.5;
interaction[[1, 1]] = Math.random() - 0.5;
interaction[[1, 2]] = Math.random() - 0.5;
interaction[[1, 3]] = Math.random() - 0.5;
interaction[[2, 0]] = Math.random() - 0.5;
interaction[[2, 1]] = Math.random() - 0.5;
interaction[[2, 2]] = Math.random() - 0.5;
interaction[[2, 3]] = Math.random() - 0.5;
interaction[[3, 0]] = Math.random() - 0.5;
interaction[[3, 1]] = Math.random() - 0.5;
interaction[[3, 2]] = Math.random() - 0.5;
interaction[[3, 3]] = Math.random() - 0.5;
//Custom rule code here (use program's rule print system for ease of use)
// -------- -------- -------- -------- -------- --------
Particle.prototype.split = function() {
particles.push(new Particle(this.pos, this.type, -this.vel));
}; //Not in use yet
Particle.prototype.update = function() {
for (var i = 0; i < particles.length; i++) {
if (!(particles[i].pos.x == this.pos.x && particles[i].pos.y == this.pos.y)) {
var ang = Math.atan2((this.pos.y - particles[i].pos.y), (this.pos.x - particles[i].pos.x));
var atr = 0;
if (this.pos.dist(particles[i].pos) <= interactionLimit && this.pos.dist(particles[i].pos) > 10) {
atr = interaction[[this.type, particles[i].type]] * (100 - (Math.abs(this.pos.dist(particles[i].pos)) - 90) + 90) / 100;
}
if (this.pos.dist(particles[i].pos) <= psize) {
atr = -(((psize / 100) * strRepPercent) - (this.pos.dist(particles[i].pos)));
} else if (this.pos.dist(particles[i].ppos) <= psize) {
atr = -(((psize / 100) * strRepPercent) - (this.pos.dist(particles[i].ppos)));
console.log("true");
} // Theoretically could improve physics if i can get it to work
this.vel.sub(createVector(Math.cos(ang), Math.sin(ang)).mult(atr));
}
}
this.vel.mult(fric);
};
Particle.prototype.update2 = function() {
this.ppos = this.pos;
this.pos.add(this.vel);
}
Particle.prototype.display = function() {
strokeWeight(2);
if (trackingMode) {
stroke(255 - backgroundCol[0], 255 - backgroundCol[1], 255 - backgroundCol[2], 10);
strokeWeight(4);
} else {
stroke(partColors[this.type][0], partColors[this.type][1], partColors[this.type][2], 100);
}
fill(partColors[this.type][0], partColors[this.type][1], partColors[this.type][2], partColors[this.type][3]);
ellipse(this.pos.x + camX, this.pos.y + camY, psize, psize);
};
var drawGrid = function() {
noStroke();
fill(255 - backgroundCol[0], 255 - backgroundCol[1], 255 - backgroundCol[2], 50);
rectMode(CENTER, CENTER);
rect(0.5 + camX, 0.5 + camY, 12, 12);
for (var i = camX; i < width * zoom; i += gridSpacing) {
stroke(255 - backgroundCol[0], 255 - backgroundCol[1], 255 - backgroundCol[2], 50);
strokeWeight(1);
line(i, 0 - width * zoom, i, height * zoom);
}
for (i = camY; i < height * zoom; i += gridSpacing) {
stroke(255 - backgroundCol[0], 255 - backgroundCol[1], 255 - backgroundCol[2], 50);
strokeWeight(1);
line(0 - height * zoom, i, width * zoom, i);
}
for (i = camX; i > 0 - width * zoom; i -= gridSpacing) {
stroke(255 - backgroundCol[0], 255 - backgroundCol[1], 255 - backgroundCol[2], 50);
strokeWeight(1);
line(i, 0 - width * zoom, i, height * zoom);
}
for (i = camY; i > 0 - height * zoom; i -= gridSpacing) {
stroke(255 - backgroundCol[0], 255 - backgroundCol[1], 255 - backgroundCol[2], 50);
strokeWeight(1);
line(0 - height * zoom, i, width * zoom, i);
}
}
var cameraHandler = function() {
translate(width / 2, height / 2);
if (keyIsPressed === true && keyCode === DOWN_ARROW || keyIsPressed === true && key === "s") {
camY -= constrain(camVel, 1.5 / zoom, maxCamSpeed / zoom);
camVel += 0.3;
camClear = true;
} else if (keyIsPressed === true && keyCode === RIGHT_ARROW || keyIsPressed === true && key === "d") {
camX -= constrain(camVel, 1.5 / zoom, maxCamSpeed / zoom);
camVel += 0.3;
camClear = true;
} else if (keyIsPressed === true && keyCode === UP_ARROW || keyIsPressed === true && key === "w") {
camY += constrain(camVel, 1.5 / zoom, maxCamSpeed / zoom);
camVel += 0.3;
camClear = true;
} else if (keyIsPressed === true && keyCode === LEFT_ARROW || keyIsPressed === true && key === "a") {
camX += constrain(camVel, 1.5 / zoom, maxCamSpeed / zoom);
camVel += 0.3;
camClear = true;
} else {
camVel = 1.5;
}
if (keyIsPressed && key === "z" || keyIsPressed && key === "=") {
zoom += 0.01 * zoom;
camClear = true;
} else if (keyIsPressed && key === "x" || keyIsPressed && key === "-") {
zoom -= 0.01 * zoom;
camClear = true;
}
zoom = constrain(zoom, 0.1, 5);
};
var specialCursor = function() {
noCursor() // Remove defualt cursor
fill(255);
ellipse((mouseX - camX) - width / 2, (mouseY - camY) - height / 2, 10, 10);
}
//Draw function ------------- ------------- ------------- ------------- ------------- ------------- -------------
function draw() {
//specialCursor();
cameraHandler();
scale(zoom);
if (!trackingMode || camClear) {
background(backgroundCol[0], backgroundCol[1], backgroundCol[2]);
if (zoom >= 1) {
drawGrid();
}
}
for (var j = 0; j < speedMultInt - 1; j++) {
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].update();
}
for (i = particles.length - 1; i >= 0; i--) {
particles[i].update2();
}
}
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].update();
}
for (i = particles.length - 1; i >= 0; i--) {
particles[i].update2();
particles[i].display();
}
if (mouseButton === LEFT && focus && keyCode === OPTION && keyIsPressed && mouseIsPressed) {
particles.push(new Particle(createVector(((mouseX - camX) - width / 2) / zoom, ((mouseY - camY) - height / 2) / zoom), typeToPlace, createVector(0, 0)));
}
removeElements();
createElement("p", "<b>Current type to place:</b> type " + (typeToPlace + 1) + " (color " + partColors[typeToPlace] + ")");
createElement("p", "<b>Population:</b> " + particles.length);
createElement("p", "<b>Camera position:</b> " + Math.round(camX) + ", " + Math.round(camY));
if (!focused) {
focus = false;
}
camClear = false;
}