-
Notifications
You must be signed in to change notification settings - Fork 0
FlowAgent Core
In GetClosestAgents()
, the agent refers to the singleton AIManager instance, and requests the closest neighbours in a certain distance. By using a singleton, the agent does not need to keep a reference to every single other agent but instead lets the manager do the heavy lifting. Depending on the amount of agents, this can still get performance-heavy, so there are certainly better ways to handle this but that would require more research.
For debugging and visualizations purposes, the agent also gets assigned a color based on how many agents are near.
private void GetClosestAgents()
{
_neighbourAgents = AIManager.Instance.GetNeighbours(this);
_neighbourCount = _neighbourAgents.Count;
float lerpProgress = (float)_neighbourCount / AIManager.Instance.TotalAgentCount * COLOR_MULTIPLIER;
Color noNeighbourColor = Color.red;
Color hasNeighbourColor = Color.green;
Color lerpedColor = Color.Lerp(noNeighbourColor, hasNeighbourColor, lerpProgress);
if(!CurrentlySelected)
SetColor(lerpedColor);
}
For the so-called "flocking" behaviour (like flocks of birds or schools of fish are known to do), 3 different parts are needed to construct a working algorithm.
First of all, alignment
makes sure every agent that's qualified as a neighbour look in roughly the same direction.
private Vector3 CalculateAlignment()
{
Vector3 alignmentVec = transform.up;
if (_neighbourCount == 0)
return alignmentVec;
foreach (var neighbour in _neighbourAgents)
{
alignmentVec += neighbour.transform.up;
}
alignmentVec /= _neighbourCount;
if(_showAlignment)
Debug.DrawRay(transform.position, alignmentVec, Color.blue);
return alignmentVec;
}
Second, cohesion
takes care of finding the middle position of the "flock" which makes sure the neighbours tend to stay together.
private Vector3 CalculateCohesion()
{
Vector3 cohesionVec = Vector3.zero;
if (_neighbourCount == 0)
return cohesionVec;
foreach (var neighbour in _neighbourAgents)
{
cohesionVec += neighbour.transform.position;
}
cohesionVec /= _neighbourCount;
cohesionVec -= transform.position;
if(_showCohesion)
Debug.DrawLine(transform.position, cohesionVec, Color.green);
return cohesionVec;
}
Lastly, there is avoidance
. This prevents agents from bunching up too close to each other.
private Vector3 CalculateAvoidance()
{
Vector3 avoidanceVec = Vector3.zero;
if (_neighbourCount == 0)
return avoidanceVec;
foreach (var neighbour in _neighbourAgents)
{
float distance = Vector3.Distance(transform.position, neighbour.transform.position);
if (distance >= Properties.AvoidanceRadius)
continue;
avoidanceVec -= (neighbour.transform.position - transform.position);
}
if(_showAvoidance)
Debug.DrawRay(transform.position, avoidanceVec.normalized, Color.red);
avoidanceVec /= _neighbourCount;
return avoidanceVec;
}
All of these aspects combined construct a flocking behaviour. It is a lot of testing & tweaking parameters to see the effects and what values provide a realistic behaviour.