Tom Says: Safe code is boring code! Why??
Previous page:
Daily Crap 2009-02-20
Next page:
Daily Crap 2009-03-13
Just a Processing sketch for animating the motions of a bunch of critters moving around a bounded 2-D field with a simple flocking algorithm (average movement directions of every nearest-neighbor pair). Really just a distraction…

int width = 800;
int height = 600;
float bouncebuffer = 0.1; // how far past the screen world boundaries are
// try making this negative!
int numcritters = 150;
int traillength = 100;
float vel = 80;
int colorlevels = 3;
int colors[] = new int[] {color(255, 0, 0), color(255, 255, 255), color(0, 0, 255)};
Critter[] critters = new Critter[numcritters];
class Critter {
public float x, y, v, angle;
private float[] xtrail, ytrail;
public Critter(float x, float y, float v, float angle) {
this.x = x;
this.y = y;
this.v = v;
this.angle = angle;
xtrail = new float[traillength];
ytrail = new float[traillength];
for(int i = 0; i < xtrail.length; i++) {
xtrail[i] = x;
ytrail[i] = y;
}
}
public void update(float seconds) {
x += v * seconds * cos(angle);
y += v * seconds * sin(angle);
Critter neighbor = nearest(this);
// collisions aren't handled right. but it's RIGHT ENOUGH, JERK
if(y < -height * bouncebuffer || y > height + height * bouncebuffer)
angle = -angle;
if(x < -width * bouncebuffer || x > width + width * bouncebuffer)
angle = PI + angle;
else {
angle += anglediff(angle, neighbor.angle) * 0.5;
angle += random(-0.3, 0.3);
}
shiftTrail();
xtrail[xtrail.length - 1] = x;
ytrail[ytrail.length - 1] = y;
}
public void draw() {
stroke(128);
for(int i = 0; i < xtrail.length - 1; i++) {
// lots of options here
//stroke(255 - abs((float) i / (float) xtrail.length - 0.5) * 2 * 255);
//stroke(255 - (float) i / (float) xtrail.length * 255);
//stroke(col(xtrail[i], ytrail[i]));
//stroke(colscale(col(xtrail[i], ytrail[i]), 1 - abs((float) i / (float) xtrail.length - 0.5) * 2));
stroke(colscale(col(x, y), 1 - abs((float) i / (float) xtrail.length - 0.5) * 2));
line(xtrail[i], ytrail[i], xtrail[i+1], ytrail[i+1]);
}
stroke(255);
//ellipse(x, y, 5, 5);
}
private void shiftTrail() {
for(int i = 0; i < xtrail.length - 1; i++) {
xtrail[i] = xtrail[i + 1];
ytrail[i] = ytrail[i + 1];
}
}
}
void setup() {
size(width, height);
for(int i = 0; i < critters.length; i++) {
critters[i] = new Critter(
//random(0, width),
//random(0, height),
width/2,
height/2,
vel,
random(0, TWO_PI));
}
// run the simulation off-screen for a bit
// so it starts interestingly
// (also interesting if you don't do this)
for(int t = 0; t < traillength * 4; t++) {
for(int i = 0; i < critters.length; i++)
critters[i].update(1.0 / frameRate);
}
last_tick = millis();
}
float last_tick = 0;
void draw() {
background(0);
float tick = millis();
for(int i = 0; i < critters.length; i++) {
critters[i].update((tick - last_tick) / 1000.0);
critters[i].draw();
}
last_tick = tick;
}
float angleshift = 0;
void keyPressed() {
angleshift += PI;
for(int i = 0; i < critters.length; i++)
critters[i].angle = angleshift;
}
// I could build a k-d tree every frame
// to make this logular instead of linear!
// but I'm also lazy
Critter nearest(Critter critter) {
// make sure there's a least one other critter
if(critters.length < 2) return null;
Critter c = critters[0];
float d = dist(critter.x, critter.y, c.x, c.y);
for(int i = 0; i < critters.length; i++) {
if(critters[i] == critter)
continue;
float d2 = dist(critter.x, critter.y, critters[i].x, critters[i].y);
if(d2 < d || c == critter) {
d = d2;
c = critters[i];
}
}
return c;
}
// returns the relative difference between two angles
float anglediff(float zero, float angle) {
float d = angle - zero;
while(d < -PI) d += PI;
while(d > PI) d -= PI;
return d;
}
// returns which color a critter should be given their location
color col(float x, float y) {
int level = (int) (y / height * colorlevels);
//int level = (int) (x / width * colorlevels);
if(level < 0) level = 0;
if(level >= colorlevels) level = colorlevels - 1;
return colors[level];
}
// scales a color by a factor
// (seems like something there's already a Processing function to do, somewhere)
color colscale(color a, float scale) {
return color(red(a) * scale, green(a) * scale, blue(a) * scale);
}
Posted Mar 10, 2009, in the evening.