topical media & game development
mobile-query-three-plugins-flocking-examples-boidflocking.js / js
// Based on http://www.openprocessing.org/visuals/?visualID=6910
// TODO pass in tQuery plugins
// * tQuery.extends for all parameters
// * .prototype function
// * bind it automatically
var Boid = function() {
var vector = new THREE.Vector3();
var _width = 500;
var _height = 500;
var _depth = 200;
var _goal;
var _acceleration;
var _neighborhoodRadius = 100;
var _maxSpeed = 2;
var _maxSteerForce = 0.1;
var _avoidWalls = false;
this.position = new THREE.Vector3();
this.velocity = new THREE.Vector3();
_acceleration = new THREE.Vector3();
Set the goal of the boid - if any
this.setGoal = function( target ){
_goal = target;
}
getter/setter on the walls
this.avoidWalls = function( value ){
if( value === undefined ) return _avoidWalls;
_avoidWalls = value;
return this;
};
Setter on world size
this.setWorldSize = function ( width, height, depth ) {
_width = width;
_height = height;
_depth = depth;
}
this.run = function ( boids ) {
if ( _avoidWalls ) {
vector.set( - _width, this.position.y, this.position.z );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.add( vector );
vector.set( _width, this.position.y, this.position.z );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.add( vector );
vector.set( this.position.x, - _height, this.position.z );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.add( vector );
vector.set( this.position.x, _height, this.position.z );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.add( vector );
vector.set( this.position.x, this.position.y, - _depth );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.add( vector );
vector.set( this.position.x, this.position.y, _depth );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.add( vector );
}/* else {
this.checkBounds();
}
*/
if ( Math.random() > 0.5 ) {
this.flock( boids );
}
this.move();
}
this.flock = function ( boids ) {
if ( _goal ) {
_acceleration.add( this.reach( _goal, 0.005 ) );
}
_acceleration.add( this.alignment( boids ) );
_acceleration.add( this.cohesion( boids ) );
_acceleration.add( this.separation( boids ) );
}
move this boid
this.move = function () {
// update velocity with _acceleration
this.velocity.add( _acceleration );
_acceleration.set( 0, 0, 0 );
// keep speed <= _maxSpeed
var speed = this.velocity.length();
if( speed > _maxSpeed ){
this.velocity.divideScalar( speed / _maxSpeed );
}
// update position with velocity
this.position.add( this.velocity );
}
if the boid is out of the world - warp it around
this.checkBounds = function () {
if ( this.position.x > _width ) this.position.x = - _width;
if ( this.position.x < - _width ) this.position.x = _width;
if ( this.position.y > _height ) this.position.y = - _height;
if ( this.position.y < - _height ) this.position.y = _height;
if ( this.position.z > _depth ) this.position.z = - _depth;
if ( this.position.z < - _depth ) this.position.z = _depth;
}
//
this.avoid = function ( target ) {
var steer = new THREE.Vector3();
steer.copy( this.position );
steer.sub( target );
steer.multiplyScalar( 1 / this.position.distanceToSquared( target ) );
return steer;
}
will steer away from the target
parameter: {[type]} target [description]
parameter: {[type]} maxDistance [description]
returns: {[type]} [description]
this.repulse = function( target, maxDistance ){
// sanity check
console.assert( target !== undefined );
console.assert( maxDistance !== undefined );
// compute distance to the target
var distance = this.position.distanceTo( target );
// if too far, do nothing
if ( distance >= maxDistance ) return;
// compute vector to steer away
var steer = new THREE.Vector3();
steer.subVectors( this.position, target );
steer.multiplyScalar( 0.5 / distance );
// add steer vector
_acceleration.add( steer );
}
this.reach = function ( target, amount ) {
var steer = new THREE.Vector3();
steer.subVectors( target, this.position );
steer.multiplyScalar( amount );
return steer;
}
this.alignment = function ( boids ) {
var boid, velSum = new THREE.Vector3(),
count = 0;
for ( var i = 0, il = boids.length; i < il; i++ ) {
if ( Math.random() > 0.6 ) continue;
boid = boids[ i ];
distance = boid.position.distanceTo( this.position );
if ( distance > 0 && distance <= _neighborhoodRadius ) {
velSum.add( boid.velocity );
count++;
}
}
if( count > 0 ){
velSum.divideScalar( count );
var l = velSum.length();
if ( l > _maxSteerForce ) {
velSum.divideScalar( l / _maxSteerForce );
}
}
return velSum;
}
this.cohesion = function ( boids ) {
var posSum = new THREE.Vector3();
var steer = new THREE.Vector3();
var count = 0;
for( var i = 0, il = boids.length; i < il; i ++ ){
if ( Math.random() > 0.6 ) continue;
var boid = boids[ i ];
var distance = boid.position.distanceTo( this.position );
if( distance > 0 && distance <= _neighborhoodRadius ){
posSum.add( boid.position );
count++;
}
}
if( count > 0 ) posSum.divideScalar( count );
steer.subVectors( posSum, this.position );
var steerLen = steer.length();
if( steerLen > _maxSteerForce ) {
steer.divideScalar( steerLen / _maxSteerForce );
}
return steer;
}
this.separation = function ( boids ) {
var posSum = new THREE.Vector3();
var repulse = new THREE.Vector3();
for ( var i = 0, il = boids.length; i < il; i ++ ) {
if( Math.random() > 0.6 ) continue;
var boid = boids[ i ];
var distance = boid.position.distanceTo( this.position );
if( distance > 0 && distance <= _neighborhoodRadius ){
repulse.subVectors( this.position, boid.position );
repulse.normalize();
repulse.divideScalar( distance );
posSum.add( repulse );
}
}
return posSum;
}
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.