Flocking is a term applied to the behavior of birds and other flying animals that are organized into a swarm or flock.
From our point of view, it is especially interesting that flocking behavior can be simulated by applying only three rules to each particle (Boid). These rules are as follows:
We will implement the rules for flocking behavior. Perform the following steps to do so:
int numParticle = 50; float radius = 5.f; float mass = 1.f;
Particle
class inside the Particle.h
header file.void flock(std::vector<Particle*>& particles); ci::Vec2f steer(ci::Vec2f target, bool slowdown); void borders(float width, float height); ci::Vec2f separate(std::vector<Particle*>& particles); ci::Vec2f align(std::vector<Particle*>& particles); ci::Vec2f cohesion(std::vector<Particle*>& particles); float maxspeed; float maxforce; ci::Vec2f vel;
maxspeed
and maxforce
at the end of the Particle
constructor inside the Particle.cpp
source file.this->maxspeed = 3.f; this->maxforce = 0.05f;
Particle
class inside the Particle.cpp
source file.void Particle::flock(std::vector<Particle*>& particles) { ci::Vec2f acc; acc += separate(particles) * 1.5f; acc += align(particles) * 1.0f; acc += cohesion(particles) * 1.0f; vel += acc; vel.limit(maxspeed); } ci::Vec2f Particle::steer(ci::Vec2f target, bool slowdown) { ci::Vec2f steer; ci::Vec2f desired = target - position; float d = desired.length(); if (d >0) { desired.normalize(); if ((slowdown) && (d <100.0)) desired *= (maxspeed*(d/100.0)); else desired *= maxspeed; steer = desired - vel; steer.limit(maxforce); } else { steer = ci::Vec2f::zero(); } return steer; } void Particle::borders(float width, float height) { if (position.x< -radius) position.x = width+radius; if (position.y< -radius) position.y = height+radius; if (position.x>width+radius) position.x = -radius; if (position.y>height+radius) position.y = -radius; }
ci::Vec2f Particle::separate(std::vector<Particle*>& particles) { ci::Vec2f resultVec = ci::Vec2f::zero(); float targetSeparation = 30.f; int count = 0; for( std::vector<Particle*>::iterator it = particles.begin(); it != particles.end(); ++it ) { ci::Vec2f diffVec = position - (*it)->position; if( diffVec.length() >0&&diffVec.length() <targetSeparation ) { resultVec += diffVec.normalized() / diffVec.length(); count++; } } if (count >0) { resultVec /= (float)count; } if (resultVec.length() >0) { resultVec.normalize(); resultVec *= maxspeed; resultVec -= vel; resultVec.limit(maxforce); } return resultVec; }
ci::Vec2f Particle::align(std::vector<Particle*>& particles) { ci::Vec2f resultVec = ci::Vec2f::zero(); float neighborDist = 50.f; int count = 0; for( std::vector<Particle*>::iterator it = particles.begin(); it != particles.end(); ++it ) { ci::Vec2f diffVec = position - (*it)->position; if( diffVec.length() >0 && diffVec.length() <neighborDist ) { resultVec += (*it)->vel; count++; } } if (count >0) { resultVec /= (float)count; } if (resultVec.length() >0) { resultVec.normalize(); resultVec *= maxspeed; resultVec -= vel; resultVec.limit(maxforce); } return resultVec; }
ci::Vec2f Particle::cohesion(std::vector<Particle*>& particles) { ci::Vec2f resultVec = ci::Vec2f::zero(); float neighborDist = 50.f; int count = 0; for( std::vector<Particle*>::iterator it = particles.begin(); it != particles.end(); ++it ) { float d = position.distance( (*it)->position ); if( d >0 && d <neighborDist ) { resultVec += (*it)->position; count++; } } if (count >0) { resultVec /= (float)count; return steer(resultVec, false); } return resultVec; }
update
method to read as followsvoid Particle::update(){ ci::Vec2f temp = position; position += vel + forces / mass; prevPosition = temp; forces = ci::Vec2f::zero(); }
drawing
method of Particle
, as follows:void Particle::draw(){ ci::gl::color(1.f, 1.f, 1.f); ci::gl::drawSolidCircle( position, radius ); ci::gl::color(1.f, 0.f, 0.f); ci::gl::drawLine(position, position+( position - prevPosition).normalized()*(radius+5.f) ); }
update
method of ParticleSystem
inside the ParticleSystem.cpp
source file, as follows:void ParticleSystem::update(){ for( std::vector<Particle*>::iterator it = particles.begin(); it!= particles.end(); ++it ){ (*it)->flock(particles); (*it)->update(); (*it)->borders(640.f, 480.f); } }
Three rules for flocking—separation, alignment, and cohesion—were implemented starting from step 4 and they were applied to each particle in step 10. In this step, we also prevented Boids from going out of the window boundaries by resetting their positions.
18.220.160.43