The enemies move in a long single-file line, like a centipede

Hello Aron,

I’m using your A* Pathfinding Project to handle enemy movement. However, when the enemies are far away from their target, they often end up following almost the exact same path, which makes the whole group move in a single line.

I’d like the enemies to spread out more while moving, so that they feel more like a large army or a group rather than a single-file line.

Do you have any recommendations or suggested approaches for achieving this?

Local avoidance may help here. If you’re not using FollowerEntity you can also use AlternativePath. There are also a myriad of other ways to accomplish this but I’d consider these the first two things to attempt.

My enemies previously used RichAI + RVOController, but when the path was too long, they would gradually end up moving in a single-file line, like a centipede.

How FollowerEntity solve this problem? What new features does FollowerEntity have compared to RichAI + RVOController? Can any of them solve this problem?

The FollowerEntity does have some mitigations for this. It by default tries to keep some distance to walls, and when using local avoidance it can detect that there many other agents around it, and will increase its desired distance to walls to compensate, and allow larger groups of agents to move around corners smoothly. It’s not perfect, but it’s usually much better than what RichAI did.

Oh wow, the author replied to me!

I recently replaced RichAI + RVOController with FollowerEntity because of the performance issues with RVOController. Most of the performance cost has gone down, but I’ve noticed that there is still a spike in RVOSystem every three frames.

I’d like to optimize or eliminate this spike. I tried updating A* Pathfinding Project to the latest version, but it didn’t seem to help.

Are there any other possible solutions?

Depends on what the spike consists of. You can use the unity profiler to find out.

I’ve noticed that almost all of the performance cost comes from the “Read agent data” part of RVOSystem.

That’s odd. That should only be there if you are using RVOController components, not if you are using the FollowerEntity. Are you sure you don’t have any RVOController components left?

The walls in my game are indeed using RVOController. Should I try removing them and see if that helps?

If I don’t use RVOController for the walls, what component should I use instead to prevent enemies from passing through them? My walls can be dynamically built and removed, but once they are placed, they remain completely static unless they are destroyed or dismantled.

The agents, when using FollowerEntity, will not be able to pass through them anyway, assuming the graph has been updated to account for them. Are you using graph updates like in Graph Updates during Runtime - A* Pathfinding Project ?

And yes, removing those RVOControllers will most likely improve performance.

I’m not currently using runtime graph updates.

If I update the graph whenever a wall is built or removed, would that also introduce a significant performance cost if walls are being built and removed very frequently?

Hard to say as it depends a lot on the graph complexity, size and frequency of updates.

As a test, I would recommend attaching the DynamicObstacle component to one of your walls and see what that does to performance.

After removing the RVOController, the large spike that occurred every three frames did indeed disappear.

Why does RVOController cause a spike every three frames? Is it because it reads the agent data once every few frames?

What kind of data is it reading exactly? And why can’t the agent data reading be distributed evenly across those three frames instead of doing it all at once?

The RVO fps is capped, since it’s not necessary to run it too often. So it’s framerate dependent, rather than once every X frames.

That particular spike is because it needs to read data from the managed RVOController components and write it to ECS entities. And this data needs to be up to date, so it can’t be copied during earlier frames.

Actual RVO calculations happen on separate worker threads (should be visible in the unity profiler). And usually takes more time than the copy.

Could the performance cost of RVOSystem be affected by other game logic?

I noticed that the shape of the RVOSystem timing graph looks very similar to the overall frame-time graph. Whenever RVOSystem has a spike, there also seems to be a large spike from some other logic.

So I’m wondering if RVOSystem’s reported cost could be influenced by other systems. For example, when my object pool is adding objects, it can take around 200 ms.

Definitely. It uses the same worker pool as the rest of unity’s job system. So other jobs could push it to take longer.

Check the Unity profiler and expand the Jobs foldout to see what’s taking time.