Search code examples
c++mathvectoralgebradirection

How can I calculate the direction vector to steer away from nearby agents


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.


Solution

  • 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;
            }