Boid simulation is the simulation of the behaviour of creatures while moving in groups. this movement pattern can be found in the school of fish, the flock of birds. Multiple creatures seem to move in harmony and look like all of them are being controlled by a single creature. This seemingly complex behaviour can be achieved by following three simple rules.
Rule 1: Boid Will Steer Towards the Centre of the Local Group
Boids will calculate the average point of all boid that are at a certain distance from it and move toward that point. This point can be found by calculating the average point as:
center=(boid1.position+boid2.position+boid3.position+...)/numberOfBoids
now calculate the direction toward it
direction=center-currentPosition
Rule 2: Boid Will Try to Avoid Colliding With Each Other
For this rule, a vector facing away from all surrounding boid within a certain distance will be calculated. Boid will steer toward this vector to avoid others.
this can be calculated as:awayVector= vectorZero-(boid1.position-current.Position)-(boid2.Position-currentPosition)-(boid3.position-currentPosition)-...
Here, all boids are at a certain fixed distance from our boid. If a boid is far, we don’t need to include it in the calculation.
Rule 3: Boids Will Try to Align with the Heading Direction of Nearby Boids
For this rule, we need to calculate the average velocity of surrounding boids and steer towards them. This will make boid align with the surrounding boids making them move in the somewhat same direction.
This heading velocity can be calculated by averaging the velocity of surrounding boids.headingVelocity=boid1.velocity+boid2.velocity+boid3.velocity+.../numberOfBoids
Using just these three simple rules is enough to make basic flock behaviour.
Implementing Boid Rules in Unity
First, make a boid class that will move the boid at a certain speed. this movement can be done in the update method. We will also need direction to determine where to move and speed to determine the speed of boid. We will have a collection of all boids in the scene.
float speed;
Vector2 direction;
public List<Boids> boidsInScene;
void Update(){
transform.Translate(direction * (speed * Time.deltaTime))
}
This will get boid moving in at a fixed direction with constant speed.
Now we need to implement three rules. Let us make three methods to achieve this.
Rule 1: Move to Centre
float moveToCenterStrength;//factor by which boid will try toward center Higher it is, higher the turn rate to move to the center
float localBoidsDistance;//effective distance to calculate the center
void MoveToCenter(){
Vector2 positionSum = transform.position;//calculate sum of position of nearby boids and get count of boid
int count = 0;
foreach (Boids boid in boidsInScene)
{
float distance = Vector2.Distance(boid.transform.position, transform.position);
if (distance <= localBoidsDistance){
positionSum += (Vector2)boid.transform.position;
count++;
}
}
if (count == 0){
return;
}
//get average position of boids
Vector2 positionAverage = positionSum / count;
positionAverage = positionAverage.normalized;
Vector2 faceDirection = (positionAverage - (Vector2) transform.position).normalized;
//move boid toward center
float deltaTimeStrength = moveToCenterStrength * Time.deltaTime;
direction=direction+deltaTimeStrength*faceDirection/(deltaTimeStrength+1);
direction = direction.normalized;
}
Rule 2: Avoid Other Boids
float avoidOtherStrength;//factor by which boid will try to avoid each other. Higher it is, higher the turn rate to avoid other.
float collisionAvoidCheckDistance;//distance of nearby boids to avoid collision
void AvoidOtherBoids(){
Vector2 faceAwayDirection = Vector2.zero;//this is a vector that will hold direction away from near boid so we can steer to it to avoid the collision.
//we need to iterate through all boid
foreach (Boids boid in boidsInScene){
float distance = Vector2.Distance(boid.transform.position, transform.position);
//if the distance is within range calculate away vector from it and subtract from away direction.
if (distance <= collisionAvoidCheckDistance){
faceAwayDirection =faceAwayDirection+ (Vector2)(transform.position - boid.transform.position);
}
}
faceAwayDirection = faceAwayDirection.normalized;//we need to normalize it so we are only getting direction
direction=direction+avoidOtherStrength*faceAwayDirection/(avoidOtherStrength +1);
direction = direction.normalized;
}
Rule 3: Align with Surrounding Boids
float alignWithOthersStrength;//factor determining turn rate to align with other boids
float alignmentCheckDistance;//distance up to which alignment of boids will be checked. Boids with greater distance than this will be ignored
void AlignWithOthers(){
//we will need to find average direction of all nearby boids
Vector2 directionSum = Vector3.zero;
int count = 0;
foreach (var boid in flockController.creaturesInScene){
float distance = Vector2.Distance(boid.transform.position, transform.position);
if (distance <= localBoidsAlignmentCheckDistance){
directionSum += boid.direction;
count++;
}
}
Vector2 directionAverage = directionSum / count;
directionAverage = directionAverage.normalized;
//now add this direction to direction vector to steer towards it
float deltaTimeStrength = alignmentStrength * Time.deltaTime;
direction=direction+deltaTimeStrength*directionAverage/(deltaTimeStrength+1);
direction = direction.normalized;
}
using these three methods we can apply the rules of boid. we will call this before moving boid i.e. in Update method
void Update{
AlignWithOthers();
MoveToCenter();
AvoidOtherBoid();
transform.Translate(direction * (speed * Time.deltaTime))
}
This will get boid moving in the flock. This complex behaviour can be simulated just by following these three simple rules. This can be used for making fish in oceans, birds flying in the sky or a simple particle system in the game.