3
\$\begingroup\$

I use use Unity's own NavMesh/AI system and I think it works pretty well. The only problem I have is that when I move large groups of units, they will find a path one by one, but it takes a really long time as you can see in the video:

https://gfycat.com/blankhalfdartfrog

To set destinations I use this:

    public bool SetDestination(Vector3 point)
    {
        if (SamplePosition(point))
        {
            agent.SetDestination(point);
            return true;
        }

        return false;
    }

I know I could wait until they all have pathPending == false, but that would mean the entire group moves with a huge delay. Is there some way I can improve or fix this issue?

Edit: It is quite simple to recreate (if you have some basic knowledge on Unity NavMesh): simply create a "click to move"-script that moves a List of units to where you clicked using the code above (just fill the list in Start on each unit). Put down a few obstacles and you're done.

\$\endgroup\$
  • \$\begingroup\$ U can use the Profiler (Ctrl + 7) and analize your frames, and see what is taking the most time. If you still don't fix it, post your findings here :D \$\endgroup\$ – Milos Romanic Dec 17 '19 at 10:42
  • \$\begingroup\$ @MilosRomanic This is not a profiler issue :) FPS is unchanged during this process. The problem prob. has something to do with how Unity manages threading for AI. \$\endgroup\$ – Majs Dec 19 '19 at 12:22
  • \$\begingroup\$ For moving masses of units, you might want to consider flow field pathfinding instead. \$\endgroup\$ – DMGregory Dec 19 '19 at 12:32
  • \$\begingroup\$ @DMGregory that is def. plan B. But since everything works so nicely already except this one scenario, I wanted to check if it could be solved. Since Ill never really get above 1000 units total. \$\endgroup\$ – Majs Dec 19 '19 at 12:33
  • \$\begingroup\$ I haven't encountered an out of the box solutions in Unity and I don't think there are, the only thing I can think of if there is any kind of a limiter value in NavMesh system. But I have tried to describe some custom solutions which I would try in my own project in case the need arises in my answer. Feel free to ask any questions regarding it below the answer. \$\endgroup\$ – Candid Moon _Max_ Dec 21 '19 at 15:46
3
+100
\$\begingroup\$

There are multiple ways you can go about it.

Specific Approaches

  1. Faking the movement in required direction while path is calculated in the background, once path is calculated the movement along the path starts.

  2. Smaller NavMeshSurface chunks. By splitting large area of a NavMesh into smaller parts - you can decrease the time required to calculate a path which would speed up processing of path queue.

[This one is quite tough. There are multiple optimizations that could be done here. Just making multiple NavMeshSurfaces won't cut it as units cannot move by default between different parts of NavMesh. But if you split NavMesh when moving units in a group you can determine in which area the destination falls in, get path points and do processing on them and recalculate path for each unit only in this "destination area"].

  1. Similarly to (1) (optimizations from (2) may apply) you could have second Navigation system that is less precise, takes less memory and/or processing to calculate initial path to start the movement. And when more precise path is calculates, you replace it.

  2. This one is just a combination of all of them. To get movement, animations ... - (1). Having second, faster navigation system from (3) will help you calculate a path which then can be used to determine which chunks from (2) are responsible for calculating more precise path. Then when you know the end destination on the first chunk of NavMesh [usually the one where unit is at the moment] you calculate a precise path to that destination and start moving accurately. During that time calculate a better path.

  3. If you are developing an RTS with lots of units. FlowField might prove useful, I suppose it uses a lot more memory than NavMesh but should be a lot faster.

  4. If you still need more optimizations for a game with thousands of units I suggest digging into DOTS. Some useful links: DOTS Navigation, zulfajuniadi Unity Ecs Navmesh.

  5. Opinion-based: I believe a complex combination of high speed - low precision NavMesh and FlowField split into chunks and loaded during run-time when required would be the best and would suit any game size.

General Optimizaitons

  • When moving a group of units all at once. A group can be formed and a path can be found for a whole group, then positions for each unit could be determined by some conditions once whole group reaches the end point. Or even last path point for each unit could be modified to it's own destination.

  • If in your game units can change direction frequently - it's better to use the techniques from (4) because recalculation of the path would be frequent as well. Thus when path is most likely to change, you don't lose processing time that was taken for a full previous path.

More Resources

I suggest using NavMeshComponents. More info about them here: Unite Europe 2017 - Finding the path: New navigation features.

|improve this answer|||||
\$\endgroup\$
0
\$\begingroup\$

You might try the following if you're units are all grouped together (moving as a single group):

  1. Have an invisible/placeholder unit which acts as the navigator
  2. Use this unit for pathfinding (only this unit will have a navigation component and pathfinding) and you will set the destination for only this unit
  3. for the rest of the units you can simply apply a primitive "Follow" behaviour (a simple lerp position will do)

That's the general idea, of course, you also can group nearby units (for example, every "n" close units can be a "group") and each group/cluster can have a single navigator while the rest simply follow it.

For example, if you have 40 units, you can have 4 groups of 10 units each and 4 navigators (1 for each group)


If you insist on having a separate navigation component for each unit, then I think you'd be better off trying 3rd party navigation solutions instead.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ This is a good answer, but could be better if you explained explicitly how this can be done using transform.SetParent(), perhaps giving a code example for maximum clarity. \$\endgroup\$ – Engineer Dec 21 '19 at 12:50
  • \$\begingroup\$ This is something I've been trying to avoid if possible, since I don't want to force players to make formations. \$\endgroup\$ – Green_qaue Dec 22 '19 at 10:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.