I have created a strategy game where the units use Unity's NavAgent pathfinding and flocking algorithms. This works well. However, I need to add queueing so that units will queue sensibly. This works most of the time, but it isn't perfect and I want to know if there's a better way of doing it.
My first draft was to simply check which unit is closest to the destination, but this caused issues because a group might be navigating around an obstacle and the unit closest is at the back of the queue... so the whole group stops.
Second draft checked the distance to destination based upon the length of the path each unit had to take. This works far more often, but sometimes still has issues. Sometimes the same problem happens, but much less often. The one who is supposed to be moving stops, and so the entire group stops.
There's also a problem I've noticed, where the waiting units could sometimes benefit from rotating, even if they shouldn't be moving. Unfortunately they sometimes get stuck and will wait before they can move, to rotate. If they could rotate when forbidden from moving it'd help considerably too.
What I need to know...
How can I make Unity NavAgent's queue, so that they will wait for the other agents closest to the destination to move first?
How can I ensure that this does not stop agents from rotating while in a queue (rotating may move them into a better position in the queue).
Code:
Unit Movement Function
private void Movement()
{
// Unit is moving.
if (moveVectors.Count > 0)
{
navAgent.isStopped = false;
// Check for whether to wait in queue.
Vector3 nextVector = transform.position;
nextVector += transform.forward * speed * Time.deltaTime;
foreach (Unit unit in list)
{
if (unit != this &&
unit.moveVectors.Count > 0 &&
Vector3.Distance(unit.transform.position, nextVector) <= (unit.footprint + footprint) &&
PathDistance(unit) < PathDistance(this))
{
navAgent.isStopped = true;
return;
}
}
}
}
There's a bit more to Movement, but it's not relevant so we'll ignore it for now.
PathDistance Function
private float PathDistance(Unit unit)
{
Vector3 startPosition = unit.transform.position;
Vector3 endPosition = unit.moveVector;
Vector3 lastPosition = startPosition;
Vector3[] path = unit.navAgent.path.corners;
float distance = 0;
for (int i = 0; i < path.Length; i++)
{
distance += Vector3.Distance(lastPosition, path[i]);
lastPosition = path[i];
}
distance += Vector3.Distance(lastPosition, endPosition);
return distance;
}
Is there a better way of achieving the result I want?
Second draft checked the distance to destination based upon the length of the path each unit had to take. This works far more often, but sometimes still has issues.
You don't say what issues. This is important, because this approach is the only sane way to begin tackling the problem. Do they still get stuck? That is probably because the shortest path is taking into account other units that are moving. You have to get the shortest path as if the map were otherwise empty. You can then prioritise who gets to move first in order of decreasing shortest-path proximity, i.e. closest first. \$\endgroup\$ – Engineer Mar 6 '18 at 7:19