Last active
June 6, 2021 07:07
-
-
Save gonzamoiguer/84f3b83a43aba66d4a9f968f435fc0b0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// by gonzalo moiguer www.gonzamoiguer.com.ar | |
// p5.js sketch | |
// simulates patterns arising from a transport network | |
// Based on this 2010 paper by Jeff Jones "Characteristics of pattern formation and evolution in approximations of Physarum transport networks." http://eprints.uwe.ac.uk/15260/1/artl.2010.16.2.pdf | |
// Also helped by Sage Jenson breakdown and awesome GPU-powered work: https://sagejenson.com/physarum | |
var mapWidth = 500; | |
var mapHeight = 500; | |
var trailMap = []; | |
var mold = []; | |
var particleCount = 5000; | |
// | |
var particleDepositStrength = 1; | |
var decaySpeed = 1.01; | |
var diffusionStrength = 0.1; | |
var sensorDistance = 1; | |
var sensorsAngle = 22; | |
var particleRotationStrength = 27; | |
// | |
var showTrailMap = false; | |
var isSimulating = true; | |
var diffusion = [ | |
1/16, 1/8, 1/16, | |
1/8, 1/4, 1/8, | |
1/16, 1/8, 1/16 | |
]; | |
function setup() { | |
createCanvas(mapWidth, mapHeight); | |
for (let i = 0; i < particleCount; i++) { | |
let temp = new Particle(); | |
mold.push(temp); | |
} | |
for (let i = 0; i < mapWidth; i++) { | |
trailMap[i] = []; // init second dimension | |
for (let j = 0; j < mapWidth; j++) { | |
trailMap[i][j] = random(0, 0.2); | |
} | |
} | |
} | |
function draw() { | |
background(0); | |
for (let i = 0; i < mapWidth; i++) { | |
for (let j = 0; j < mapWidth; j++) { | |
// 5- diffuse | |
if (isSimulating) { | |
if (i > 1 && i < mapWidth - 2 && j > 1 && j < mapHeight - 2) { | |
let suma = 0; | |
suma += diffusion[0] * trailMap[i - 1][j - 1]; | |
suma += diffusion[1] * trailMap[i] [j - 1]; | |
suma += diffusion[2] * trailMap[i + 1][j - 1]; | |
suma += diffusion[3] * trailMap[i - 1][j]; | |
suma += diffusion[4] * trailMap[i] [j]; | |
suma += diffusion[5] * trailMap[i + 1][j]; | |
suma += diffusion[6] * trailMap[i - 1][j + 1]; | |
suma += diffusion[7] * trailMap[i] [j + 1]; | |
suma += diffusion[8] * trailMap[i + 1][j + 1]; | |
trailMap[i][j] = suma; | |
} | |
// 6- decay | |
trailMap[i][j] /= decaySpeed; | |
} | |
// show | |
if (showTrailMap) { | |
let color = trailMap[i][j] * 255; | |
stroke(color, 0, 0); | |
point(i, j); | |
} | |
} | |
} | |
noStroke(); | |
fill(255, 255, 255, 25); | |
for (let i = 0; i < mold.length; i++) { | |
if (!mold[i].alive) continue; | |
if (isSimulating) { | |
mold[i].tick(); | |
mold[i].show(); | |
} | |
} | |
} | |
function keyPressed() { | |
if (isSimulating) { | |
showTrailMap = true; | |
isSimulating = false; | |
} else { | |
showTrailMap = false; | |
isSimulating = true; | |
} | |
} | |
function Particle() { | |
this.alive = true; | |
this.pos = createVector(random(50, mapWidth - 50), random(50, mapHeight - 50)); | |
//this.pos = createVector(width/2,height/2); | |
//this.acceleration = createVector(0,0) | |
this.speed = random(0.5, 1.5); | |
this.maxspeed = 4; | |
//this.maxforce = 0.1; | |
this.heading = random(); | |
this.show = function() { | |
//point(this.pos.x, this.pos.y); | |
ellipse(this.pos.x, this.pos.y, 3); | |
} | |
this.tick = function() { | |
if (!this.alive) return; | |
// 1- sense | |
this.maxSense = 0; | |
this.maxSenseDir = 0; | |
//left | |
let radAngle = radians(this.heading - sensorsAngle); | |
let sensorX = round(this.pos.x + (sensorDistance * cos(radAngle))); | |
let sensorY = round(this.pos.y + (sensorDistance * sin(radAngle))); | |
let sensorRead = trailMap[constrain(sensorY, 0, mapWidth - 1)][constrain(sensorX, 0, mapHeight - 1)]; | |
if (sensorRead > this.maxSense) { | |
this.maxSense = sensorRead; | |
this.maxSenseDir = -1; | |
} | |
// center | |
radAngle = radians(this.heading); | |
sensorX = round(this.pos.x + (sensorDistance * cos(radAngle))); | |
sensorY = round(this.pos.y + (sensorDistance * sin(radAngle))); | |
sensorRead = trailMap[constrain(sensorY, 0, mapWidth - 1)][constrain(sensorX, 0, mapHeight - 1)]; | |
if (sensorRead >= this.maxSense) { | |
this.maxSense = sensorRead; | |
this.maxSenseDir = 0; | |
} | |
// right | |
radAngle = radians(this.heading + sensorsAngle); | |
sensorX = round(this.pos.x + (sensorDistance * cos(radAngle))); | |
sensorY = round(this.pos.y + (sensorDistance * sin(radAngle))); | |
sensorRead = trailMap[constrain(sensorY, 0, mapWidth - 1)][constrain(sensorX, 0, mapHeight - 1)]; | |
if (sensorRead > this.maxSense) { | |
this.maxSense = sensorRead; | |
this.maxSenseDir = 1; | |
} | |
// 2- rotate | |
this.heading += particleRotationStrength * this.maxSenseDir; | |
// 3- move | |
radAngle = radians(this.heading); | |
this.pos.x += this.speed * cos(radAngle); | |
this.pos.y += this.speed * sin(radAngle); | |
// collision dead | |
if (this.pos.x <= 0 || this.pos.x >= mapWidth || this.pos.y <= 0 || this.pos.y >= mapHeight) { | |
this.alive = false; | |
} | |
// 4- deposit material | |
if (this.alive) { | |
trailMap[constrain(round(this.pos.x), 0, mapWidth - 1)] | |
[constrain(round(this.pos.y), 0, mapHeight - 1)] += particleDepositStrength; | |
} else { | |
trailMap[constrain(round(this.pos.x), 0, mapWidth - 1)] | |
[constrain(round(this.pos.y), 0, mapHeight - 1)] = 0; // les aviso que todo mal | |
} | |
} | |
/* | |
this.seek = function(target) { | |
this.desired = p5.Vector.sub(target, this.pos); | |
this.desired.normalize(); | |
this.desired.mult(this.maxspeed); | |
this.steer = p5.Vector.sub(this.desired,this.velocity); | |
this.steer.limit(this.maxforce); | |
applyForce(steer); | |
} | |
this.applyForce = function(force) { | |
this.acceleration.add(force); | |
} | |
*/ | |
} | |
function mousePressed() { | |
for (let i = 0; i < mapWidth; i++) { | |
for (let j = 0; j < mapWidth; j++) { | |
if (dist(i, j, mouseX, mouseY) < 10) { | |
trailMap[i][j] = 99900; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment