We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › Simple Boid Sketch
Page Index Toggle Pages: 1
Simple Boid Sketch (Read 7151 times)
Simple Boid Sketch
Oct 23rd, 2007, 11:44pm
 
I wanted to mess around with some basic flocking behavior so I implemented a simple boids algorithm. It works, however it is pretty slow (anything above 40 boids makes it pretty choppy). I figure this is partially because Processing is built on top of Java, but only 40 boids seems pretty slow.

When I restructure the main loop to something that appears would be faster, the simulation runs at 60 fps but in slow motion. I think it has something to do with the way the draw function is called, but I can't figure out the issue exactly.

I know the code is kinda crappy and not optimized, so please pardon the mess.

Code:

// Flocking 1

// ************************* DRAWING VARIABLES **************************
final int WINDOW_WIDTH = 1000;
final int WINDOW_HEIGHT = 800;
final int FRAME_RATE = 60;

final int NUM_BOIDS = 40;
final int CENTER_PULL_FACTOR = 80000;
final float BOUNCE_ABSORPTION = 0.75;

final color backColor = color(0, 0, 0);

class Vector
{
float x, y;

public Vector()
{
x = 0;
y = 0;
}

public Vector(float initX, float initY)
{
x = initX;
y = initY;
}
} // end class Vector

class Boid
{
final int TRAIL_SCALE = 35;

color myColor = color(255, 255, 255);
int mySize = 2;

float xpos, ypos;
float vx, vy;

void drawMe()
{
stroke(myColor);
strokeWeight(mySize+3*sqrt(vx*vx+vy*vy));

line(xpos, ypos, xpos-TRAIL_SCALE*vx, ypos-TRAIL_SCALE*vy);
}

} // end class Boid


// ************************* GLOBAL VARIABLES **************************


Boid[] flock = new Boid[NUM_BOIDS];
Vector v1 = new Vector();
Vector v2 = new Vector();
Vector v3 = new Vector();
Vector v4 = new Vector();


void setup()
{
size(WINDOW_WIDTH, WINDOW_HEIGHT);
background(backColor);

randomSeed(int(random(1,1000)));

for(int i=0; i<NUM_BOIDS; ++i)
{
flock[i] = new Boid();
flock[i].xpos = random(0, WINDOW_WIDTH);
flock[i].ypos = random(0, WINDOW_HEIGHT);

flock[i].vx = random(-0.5, 0.5);
flock[i].vy = random(-0.5, 0.5);

} // end for

frameRate(FRAME_RATE);
smooth();
}


void draw()
{
background(backColor);

for (int i=0; i<NUM_BOIDS; ++i)
{
flock[i].drawMe();
updateFlock();
} // end for
}

void updateFlock()
{
for (int i=0; i<NUM_BOIDS; ++i)
{
v1 = rule1(flock[i]);
v2 = rule2(flock[i]);
v3 = rule3(flock[i]);
v4 = rule4(flock[i]);

// add vectors to velocities
flock[i].vx += v1.x + v2.x + v3.x + v4.x;
flock[i].vy += v1.y + v2.y + v3.y + v4.y;

limitVelocity(flock[i]);

// update new position with previously calculated velocities
flock[i].xpos += flock[i].vx;
flock[i].ypos += flock[i].vy;

if (flock[i].xpos < 0 || flock[i].xpos > WINDOW_WIDTH)
flock[i].vx = -flock[i].vx*BOUNCE_ABSORPTION;

if (flock[i].ypos < 0 || flock[i].ypos > WINDOW_HEIGHT)
flock[i].vy = -flock[i].vy*BOUNCE_ABSORPTION;

} // end for
}

void limitVelocity(Boid b)
{
float vlim = 1.5;
Vector v = new Vector();

float velocity = sqrt(sq(b.vx) + sq(b.vy));

if (velocity > vlim)
{
float vx = (b.vx/velocity)/vlim;
float vy = (b.vy/velocity)/vlim;
b.vx = vx;
b.vy = vy;
}

} // end limitVelocity()


Vector rule1(Boid b)
{
Vector pc = new Vector();

for (int i=0; i < NUM_BOIDS; ++i)
{
if (b != flock[i])
{
pc.x += flock[i].xpos;
pc.y += flock[i].ypos;
} // end if
} // end for

pc.x /= (NUM_BOIDS-1);
pc.y /= (NUM_BOIDS-1);

pc.x = (pc.x - b.xpos) / CENTER_PULL_FACTOR;
pc.y = (pc.y - b.ypos) / CENTER_PULL_FACTOR;

return pc;
} // end rule1()

Vector rule2(Boid b)
{
Vector v = new Vector();

for (int i=0; i < NUM_BOIDS; ++i)
{
if (b != flock[i])
{
if (distance2d(b, flock[i]) < 20)
{
v.x -= flock[i].xpos - b.xpos;
v.y -= flock[i].ypos - b.ypos;
} // end if
} // end if
} // end for

return v;
} // end rule2()

Vector rule3(Boid b)
{
Vector v = new Vector();

for (int i=0; i < NUM_BOIDS; ++i)
{
if (b != flock[i])
{
v.x += b.vx;
v.y += b.vy;
} // end if
} // end for

v.x /= (NUM_BOIDS - 1);
v.y /= (NUM_BOIDS - 1);

v.x = (v.x - b.vx)/8;
v.y = (v.y - b.vy)/8;

return v;
} // end rule3()


Vector rule4(Boid b)
{
Vector t = new Vector(0,0);
//return t;

Vector v = new Vector();

v.x = (mouseX - b.xpos) / CENTER_PULL_FACTOR;
v.y = (mouseY - b.ypos) / CENTER_PULL_FACTOR;

return v;

} // end rule4()


float distance2d(Boid v1, Boid v2)
{
float x = abs(v1.xpos - v2.xpos);
float y = abs(v1.ypos - v2.ypos);

return((sqrt(x*x + y*y)));
}
Re: Simple Boid Sketch
Reply #1 - Oct 23rd, 2007, 11:49pm
 
I get the same slow motion result when I changed the code like so:

draw():
Code:

void draw()
{
background(backColor);
updateFlock();
}


and updateFlock():
Code:

void updateFlock()
{
for (int i=0; i<NUM_BOIDS; ++i)
{
v1 = ...
.
.
flock[i].drawMe();
} // end for
}

(So here each boid is updated then drawn)

What exactly is going on here? Any way to 'fix' this?

I know that each additional boid means another iteration over the array for all 4 rules, but something just doesn't seem to be behaving here.
Re: Simple Boid Sketch
Reply #2 - Oct 24th, 2007, 4:29am
 
hi,

not a specific answer to your question... but your code really inspired me, so I hacked it and came up with this.
Added obsticles and predators, including a new rule for the boids. Also made some more of the parameters variable. you can turn off/on obsticles with 'o' and the mouse follower is turned off with spacebar.
I solved the speed issues with removing unnecessary nested for-loops and getting rid of the return in the often used functions.

http://www.extrapixel.ch/processing/boids/
Re: Simple Boid Sketch
Reply #3 - Oct 24th, 2007, 10:10pm
 
Hey thanks for your post, the updates you made are pretty neat! I looked at your code and made a bunch of updates and tweaks to mine, fixing the speed problem in the process. I don't have webhosting anywhere so sorry about the huge code posting, but here is where I'm at now.

Left click to attract, right click to scatter.

Code:

// Flocking 1
//
// Built from Conrad Parker's boid pseudocode: http://www.vergenet.net/~conrad/boids/pseudocode.html
// Code help from extrapixel: http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1193175897

// ************************* DRAWING VARIABLES **************************
final int WINDOW_WIDTH = 600;
final int WINDOW_HEIGHT = 400;
final int FRAME_RATE = 100;

int NUM_BOIDS = 400;
int CENTER_PULL_FACTOR = 300; // 300
int MOUSE_PULL_FACTOR = 400; // 400
float BOUNCE_ABSORPTION = 0.75; // 0.75
int DIST_THRESHOLD = 4; // 4

float r1 = 1.0; // pull to center of flock // 1.0
float r2 = 0.8; // avoid bunching up // 0.8
float r3 = 0.1; // match average flock speed // 0.1
float r4 = 1.0; // go to mouse // 1.0

PFont font;

final color backColor = color(0, 0, 0);

class Vector
{
float x, y;

public Vector()
{
x = 0;
y = 0;
}

public Vector(float initX, float initY)
{
x = initX;
y = initY;
}
} // end class Vector

class Boid
{
final int TRAIL_SCALE = 1;

Vector v1 = new Vector();
Vector v2 = new Vector();
Vector v3 = new Vector();
Vector v4 = new Vector();

color myColor = color(random(185,255));
//color myColor = color(255, 255, 255);

int mySize =1;

float xpos, ypos;
float vx, vy;

void drawMe()
{
stroke(myColor);
//strokeWeight(1);
line(xpos, ypos, xpos-TRAIL_SCALE*vx, ypos-TRAIL_SCALE*vy);
}

void updateBoid()
{
v1.x=v1.y=v2.x=v2.y=v3.x=v3.y=v4.x=v4.y;

rule1();
rule2();
rule3();
rule4();

// add vectors to velocities
vx += r1*v1.x + r2*v2.x + r3*v3.x + r4*v4.x;
vy += r1*v1.y + r2*v2.y + r3*v3.y + r4*v4.y;

limitVelocity();

xpos += vx;
ypos += vy;

if (xpos < 0 || xpos > WINDOW_WIDTH)
vx = -vx*BOUNCE_ABSORPTION;

if (ypos < 0 || ypos > WINDOW_HEIGHT)
vy = -vy*BOUNCE_ABSORPTION;
}

void limitVelocity()
{
float vlim = 20 ;
Vector v = new Vector();

float velocity = sqrt(sq(vx) + sq(vy));

if (velocity > vlim)
{
vx = (vx/velocity)/vlim;
vy = (vy/velocity)/vlim;
}

}

void rule1()
{
for (int i=0; i < NUM_BOIDS; ++i)
{
if (this != flock[i])
{
v1.x += flock[i].xpos;
v1.y += flock[i].ypos;
} // end if
} // end for

v1.x /= (NUM_BOIDS-1);
v1.y /= (NUM_BOIDS-1);

v1.x = (v1.x - xpos) / CENTER_PULL_FACTOR;
v1.y = (v1.y - ypos) / CENTER_PULL_FACTOR;
} // end rule1()

void rule2()
{
v2.x = 0;
v2.y = 0;
for (int i=0; i < NUM_BOIDS; ++i)
{
if (this != flock[i])
{
if (dist(xpos, ypos, flock[i].xpos, flock[i].ypos) < DIST_THRESHOLD)
{
v2.x -= flock[i].xpos - xpos;
v2.y -= flock[i].ypos - ypos;
} // end if
} // end if
} // end for

} // end rule2()

void rule3()
{
for (int i=0; i < NUM_BOIDS; ++i)
{
if (this != flock[i])
{
v3.x += flock[i].vx;
v3.y += flock[i].vy;
} // end if
} // end for

v3.x /= (NUM_BOIDS - 1);
v3.y /= (NUM_BOIDS - 1);

v3.x = (v3.x - vx)/2;
v3.y = (v3.y - vy)/2;
} // end rule3()


void rule4()
{
v4.x = 0;
v4.y = 0;
v4.x = (mouseX - xpos) / MOUSE_PULL_FACTOR;
v4.y = (mouseY - ypos) / MOUSE_PULL_FACTOR;
} // end rule4()
} // end class Boid
Re: Simple Boid Sketch
Reply #4 - Oct 24th, 2007, 10:11pm
 
Code:

Boid[] flock = new Boid[NUM_BOIDS];

void setup()
{
size(WINDOW_WIDTH, WINDOW_HEIGHT);
background(backColor);

randomSeed(int(random(1,1000)));

font = createFont("Courier", 12);

for(int i=0; i<NUM_BOIDS; ++i)
{
flock[i] = new Boid();
flock[i].xpos = random(0, WINDOW_WIDTH);
flock[i].ypos = random(0, WINDOW_HEIGHT);

flock[i].vx = random(-0.5, 0.5);
flock[i].vy = random(-0.5, 0.5);

} // end for

frameRate(FRAME_RATE);
noSmooth();
}


void draw()
{
//background(backColor);
background(50,50,50);

// r1 = pull to center of flock
// r2 = avoid bunching up
// r3 = match average flock speed
// r4 = go to mouse
if (mousePressed == true)
{
if (mouseButton == LEFT) // migrate towards mouse and compress
{
r1 = 1.0;
r2 = 0.2;
r3 = 0.1;
r4 = 1;
}
else // mouseButton == RIGHT // scatter
{
DIST_THRESHOLD = 22;
r1 = -0.1;
r2 = 0.1;
r3 = 0.07;
r4 = -0.1;
}
}
else // normal behavior
{
DIST_THRESHOLD = 4;
r1 = 1.0;
r2 = 0.8;
r3 = 0.1;
r4 = 0.05;
}


for (int i=0; i<NUM_BOIDS; ++i)
{
flock[i].updateBoid();
flock[i].drawMe();
} // end for

fill(150);
textFont(font);
text("FPS: " + int(frameRate), 10, height-12);
}


Still kinda messy (especially input handling), but it works pretty well. The only thing that seems to be missing is getting the boids to flock in a circle around the cursor. Like if you just hold the left mouse button for a while, the boids would eventually fall into an orbit around the mouse. Experimental Gameplay Project game Attack of the Killer Swarm has this behavior, not sure how that was implemented.
Re: Simple Boid Sketch
Reply #5 - Oct 29th, 2007, 9:42pm
 
hey, what's the copyrights on the code you posted initially? I would like to use it in a school project.

here's my newest version:
http://www.extrapixel.ch/processing/boids3d/

any success in the orbiting behaviour?
Re: Simple Boid Sketch
Reply #6 - Oct 29th, 2007, 9:49pm
 
err... these openGL applets don't seem to work online. so, download here:
http://www.extrapixel.ch/processing/boids3d_12.zip
Re: Simple Boid Sketch
Reply #7 - Oct 30th, 2007, 12:20am
 
extrapixel wrote on Oct 29th, 2007, 9:42pm:
hey, what's the copyrights on the code you posted initially I would like to use it in a school project.

here's my newest version:
http://www.extrapixel.ch/processing/boids3d/

any success in the orbiting behaviour


The WTFPTL (http://sam.zoy.org/wtfpl/) works for me. I'd prefer if you kept a link to this thread and / or my email address tmelot at gmail dot com just so interested people could contact me if they wanted...but it is the WTFPTL so do what ya want =). What kind of project you going to use this for I'm interested in what you come up with!

Good job with your updates. I've actually been trying to come up with gameplay prototypes I could turn this into (trying to get a job in the industry right now actually). Your 3d version's use of attractors and repulsors is similar to something I was considering trying in 2d.

Haven't had time to mess with orbiting. I really don't know how I'd solve this problem. Perhaps some sort of inverse square falloff rule based on mouse position I'll have to think about it for a while.
Re: Simple Boid Sketch
Reply #8 - Nov 1st, 2007, 11:58pm
 
wtfptl sounds good Smiley
i uploaded some results here:
http://www.youtube.com/extrapixel83
Re: Simple Boid Sketch
Reply #9 - Aug 5th, 2008, 9:48am
 
Looks cool guys.
I also experimented with some boid flocking in a project I did a while back
http://web.arch.usyd.edu.au/~ykol3681/Predray/applet/applet.html
I haven't tried doing it in 3D though.
Re: Simple Boid Sketch
Reply #10 - Sep 1st, 2008, 3:51am
 
I am playing around with the boids example provided by Daniel Shiffman in the examples - if I wanted to render a "crosshair" or some other object at the vector that represents the "cohesion" vector, how would I do this? I am new to processing ... just trying to understand where in the program this vector is stored so I can render it visible...thanks for your help in advance...
Page Index Toggle Pages: 1