xxxxxxxxxx
int rx = 100;
int ry = 180;
Walker[] w;
PVector begin;
/*=============================*/
void setup() {
size(700, 700);
colorMode(HSB);
noStroke();
begin = new PVector(width/2, 0.73*height, 0);
beginBrain();
}
/*=============================*/
void draw() {
for (int i = 0; i < w.length; i++) {
w[i].move();
w[i].checkEdges();
w[i].display();
}
}
/*=============================*/
void mousePressed() {
beginBrain();
}
/*=============================*/
void beginBrain() {
// clear background
background(250);
// create walkers
w = new Walker[10];
for (int i = 0; i < w.length; i++) {
w[i] = new Walker(i < w.length/2 ? true : false);
}
}
/*=============================*/
class Walker {
PVector pos, vel, acc;
int diam;
int counter = 50; // number of frames until it turns
boolean left; // wether it's part of the left or right side of the brain
/*--------*/
Walker(boolean left_) {
pos = new PVector(width/2, height/2, 0); // midle of the screen
vel = PVector.fromAngle(random(TWO_PI)); // velocity with random direction
acc = new PVector(0, 0, 0); // no acceleration
diam = 30;
left = left_;
}
/*--------*/
void move() {
vel.add(acc);
vel.limit(1);
pos.add(vel);
counter -= 1;
if (counter == 0) {
turn();
}
}
/*--------*/
void display() {
pushMatrix();
translate(pos.x, pos.y);
rotate(vel.heading());
if (left) {
drawLeft();
} else {
drawRight();
}
popMatrix();
}
/*--------*/
void drawLeft() {
fill(50, 50);
ellipse(0, 0, diam, diam+3);
fill(255, 200);
ellipse(0, 0, diam, diam);
}
/*--------*/
void drawRight() {
fill(75, 15);
ellipse(0, 0, diam-5, diam+5);
fill((frameCount/2)%255, 20, 255);
ellipse(0, 0, diam, diam);
}
/*--------*/
void turn() {
int sign = random(1) > 0.5 ? -1 : 1; // chose a random direction (left or right turn)
float theta = vel.heading() + sign*random(HALF_PI, PI); // turn with a random angle
// update acceleration direction
acc = PVector.fromAngle(theta);
// update acceleration magnitude (according to how much it turned)
float dif = PVector.angleBetween(acc, vel);
dif = map(dif, 0, PI, 0.1, 0.001);
acc.setMag(0.1);
counter = (int) random(40, 70); // generate a new counter
}
/*--------*/
void checkEdges() {
if (left && pos.x > width/2 - diam/2) { // keep left walkers on the left
pos.x = width/2 - diam/2;
turn();
} else if (!left && pos.x < width/2 + diam/2) { // keep right walkers on the right
pos.x = width/2 + diam/2;
turn();
} else { // keep it inside of a cardioid
float theta = atan2(pos.y - begin.y, pos.x - begin.x); // angle from the begining
float x = begin.x + rx*(1 + cos(theta + HALF_PI))*cos(theta); // x of the cardioid with angle theta
float y = begin.y + ry*(1 + cos(theta + HALF_PI))*sin(theta); // y of the cardioid with angle theta
float distance = dist(begin.x, begin.y, pos.x, pos.y); // distance from position to the beginning
float radius = dist(begin.x, begin.y, x, y); // distance form the cardioid to the beginning
if (distance >= radius) { // if it's outside of the cardioid turn towards the center
float angle = atan2(height/2-y, width/2-x);
acc.set(cos(angle), sin(angle), 0);
}
}
}
}