So I am trying to make a boids simulation. I am trying to implement the first rule which is that each boid must steer away from nearby boids. I have all boids in a std::vector
called boids. Each boids has a std::vector
called withinSensoryRange
which holds all boids which are within the boids sensory range. The way I went about this is to calculate the closest boid in the withinSensoryRange
vector for each boid and then try to steer away from that boid.
for (auto& boid : boids)
{
if (!boid->withinSensoryRange.empty())
{
Boid* closest = boid->withinSensoryRange[0];
float lowest = INFINITY;
for (auto& boidwithinRange : boid->withinSensoryRange)
{
float distance = sqrtf((boid->position.x - boidwithinRange->position.x) * (boid->position.x - boidwithinRange->position.x) +
(boid->position.y - boidwithinRange->position.y) * (boid->position.y - boidwithinRange->position.y));
if (distance < lowest)
{
lowest = distance;
closest = boidwithinRange;
}
}
///THIS BIT BELOW IS THE ONE THAT DOES NOT WORK PROPERLY.
///I have verified that everything else works properly.
float difference = boid->GetDirectionAngle() - closest->GetDirectionAngle();
if (difference != 0)
boid->rotationAngle += (1.0f / difference) * 0.009f;
}
}
So I thought that if I add the inverse of difference then the more the difference is the slowley they would turn and vice-versa. I also times it by 0.009f to make them less mobile. I can't tell why but this approach does not really seem to be working. I need a proper way to calculate direction vector that is steering away from the closest
boid.
By the way, boid.GetDirectionAngle()
returns boid.rotationAngle + 90 degrees
, so I am checking direction angle but adding to rotationAngle
.
Thanks for helping.
After a few days of struggle I finally got it working. I got the idea from this paper. Particularly this sentence:
Each boid considers its distance to other flock mates in its neighborhood and applies a repulsive force in the opposite direction, scaled by the inverse of the distance.
The code bellow does exactly what the above sentence says.
for (auto& arrow : arrows)
{
olc::vf2d totalInfluence;
for (auto& inRange : arrow->withinFovRange)
{
float distance = GetDistance(arrow->position, inRange->position);
olc::vf2d vecToBoidInRange = (arrow->position - inRange->position).norm();
if (distance != 0)
vecToBoidInRange *= (1.0f / distance);
totalInfluence += vecToBoidInRange;
}
arrow->rotationAngle += std::atan2(totalInfluence.y, totalInfluence.x) * rotationMobility;
}