Javascript Boids
October 17, 2008
Boids are a way to simulate swarm behaviour using 3 simple rules. I’d previously implemented Boids in Python, and was really impressed with the results. When I heard about the javascript vector graphics library Raphaël I thought it would be a good opportunity to port my original code to javascript. If you just want to see the boids in action you can jump right to the boids demonstration.
At the heart of the boids implementation are the boid objects. The constructor function is shown below, and basically just sets up a starting position, size, and velocity, and creates an Raphaël circle:
var Boid = function(x, y, size) {
this.x = x;
this.y = y;
this.xVelocity = 1;
this.yVelocity = -1;
this.circle = paper.circle(x, y, size).attr({fill: '#FF0000'});
}
Here’s the boids move away function, which makes sure that the boids don’t crowd each other:
Boid.prototype.moveAway = function(boids, minDistance) {
var distanceX = 0;
var distanceY = 0;
var numClose = 0;
for(var i = 0; i < boids.length; i++) {
var boid = boids[i];
if(boid.x == this.x && boid.y == this.y) continue;
var distance = this.distance(boid)
if(distance < minDistance) {
numClose++;
var xdiff = (this.x - boid.x);
var ydiff = (this.y - boid.y);
if(xdiff >= 0) xdiff = Math.sqrt(minDistance) - xdiff;
else if(xdiff < 0) xdiff = -Math.sqrt(minDistance) - xdiff;
if(ydiff >= 0) ydiff = Math.sqrt(minDistance) - ydiff;
else if(ydiff < 0) ydiff = -Math.sqrt(minDistance) - ydiff;
distanceX += xdiff;
distanceY += ydiff;
}
}
if(numClose == 0) return;
this.xVelocity -= distanceX / 5;
this.yVelocity -= distanceY / 5;
}
The move closer function, which causes the boids to attract one another:
Boid.prototype.moveCloser = function(boids, distance) {
if(boids.length < 1) return
var avgX = 0;
var avgY = 0;
for(var i = 0; i < boids.length; i++) {
var boid = boids[i];
if(boid.x == this.x && boid.y == this.y) continue;
if(this.distance(boid) > distance) continue;
avgX += (this.x - boid.x);
avgY += (this.y - boid.y);
}
avgX /= boids.length;
avgY /= boids.length;
distance = Math.sqrt((avgX * avgX) + (avgY * avgY)) * -1.0
if(distance == 0) return;
this.xVelocity= Math.min(this.xVelocity + (avgX / distance) * 0.15, maxVelocity)
this.yVelocity = Math.min(this.yVelocity + (avgY / distance) * 0.15, maxVelocity)
}
And the move with function, which causes all the boids to generally move in the same direction:
Boid.prototype.moveWith = function(boids, distance) {
if(boids.length < 1) return
// calculate the average velocity of the other boids
var avgX = 0;
var avgY = 0;
for(var i = 0; i < boids.length; i++) {
var boid = boids[i];
if(boid.x == this.x && boid.y == this.y) continue;
if(this.distance(boid) > distance) continue;
avgX += boid.xVelocity;
avgY += boid.yVelocity;
}
avgX /= boids.length;
avgY /= boids.length;
distance = Math.sqrt((avgX * avgX) + (avgY * avgY)) * 1.0
if(distance == 0) return;
this.xVelocity= Math.min(this.xVelocity + (avgX / distance) * 0.05, maxVelocity);
this.yVelocity = Math.min(this.yVelocity + (avgY / distance) * 0.05, maxVelocity);
}
With just those simple three rules some quite complex and realistic looking swarm behaviour emerges!
View the boids in action (tested on Firefox 3).
Download the source code: boids.js.
I’ve been reading up on related emergence concepts and I want to implement my own simulation of some of this stuff. Thanks for posting this, seems like the raphael library is a great library to use!
Comment by Shaon — November 20, 2008 @ 7:24 am
This look like good stuff! I’m planning on having a go converting this into 3D, and using it to control sprite movement in Apple’s Quartz Composer application.
Thanks for sharing!
a|x
Comment by a|x — December 15, 2008 @ 12:57 pm
Pretty cool demo. I haven’t done anything with Raphael yet, but it seems pretty fast updating the canvas. I have to give it a try.
Have you tried doing animation on the DOM?
Comment by Eneko Alonso — January 3, 2009 @ 5:45 am
Have a look at dojo.gfx, too.
Comment by someone — February 2, 2009 @ 1:55 pm
Oct 2009? so this is implementation is in the future?
john resig has a similar demo as a side effect of his implementation of processing:
http://ejohn.org/apps/processing.js/examples/topics/flocking.html
Comment by Adamantium — February 10, 2009 @ 12:35 am
oops.. that processing link should be
http://processing.org/learning/topics/flocking.html
Comment by Adamantium — February 10, 2009 @ 12:38 am
@Adamantium: Not sure how I made the 2009 mistake, fixed now. Thanks for the processing link too!
Comment by Ben — February 15, 2009 @ 11:39 pm
Hi, I took your demo and decided to add a few extra bits of eye candy. I’ve credited you guys for the use of source, hope it’s ok.
http://proceduralgraphics.blogspot.com/2010/06/flock-in-cloudy-blue-sky.html
Comment by Dave Lawrence — June 19, 2010 @ 4:10 pm
@Dave: No problem. You’ve done a great job!
Comment by Ben — June 19, 2010 @ 4:32 pm