How to prevent my NPCs from clumping up while chasing a common target.

AI & Navigation seems to be entirely about NavMesh Agent and machine learning, which are not applicable to my game. Sorry if this is the wrong forum for this post.

I am working on the enemies for my game, and they are pretty simple as of right now. The characters take in a desired movement vector I call “wishDir” and it walks in that direction. I have an ai brain that sets wishDir to a direction to chase the player up to a certain distance, then attack. If the player gets too close then the enemy will back off. Because I don’t use NavMesh Agents to move my NPCs, I need another way to keep them from clumping up and overlapping, without the use of physics. I would like for them to know of the position of other NPCs and attempt to spread out both as they position themselves to attack the player. Eventually I would like to build off of this as well and say, make enemies strafe around a bit.

This video shows an example of the enemies clumping up. I would like for the enemies to spread out as they exit those spawner rooms and attempt to stay spread out whenever they are moving. I am not sure where to start implementing this. Any suggestions appreciated!

It’s an interesting problem… I’ve always just made them keep repositioning randomly at a range from the player, and tend to pick other positions near where they are to minimize movement.

To get a good “group think” scatter, you’re gonna have to have a centralized script orchestrating where everybody goes.

One idea would be to have a “attack sector” manager script on your player, and it keeps track of who might be currently using an attack sector. Think of attack sectors as slices of pie going around you. Let’s just say 12 sectors like an analog clock.

Enemy 1 would say “I want to attack the player!” and the manager would say “Okay, go to sector 5 and attack from there.”

Next enemy would say the same thing and the manager would give him another slice.

The manager could pick randomly from all available slices (let’s say he picks 3, 6, and 9, then choose whichever of those three random slices is closest to the requesting enemy.

That would have a tendency to make enemies attack you from the side they approach, as much as possible, rather than run right by you to take up an attack point on the other side (even though they might occasionally do that if the randoms are bad).

2 Likes

I think this is a little bit different from what I am trying to do, but it is a really cool idea. For now my ai are kinda using steering behaviors mixed with navigation to a specific point. I feel like a solution to making the baddies not overlap is probably only an additional steering behavior instead of a different goal endpoint. Formations like your suggestion, do make a lot of sense as entirely different target positions. I’ll be experimenting with this and as I learn more I will come back and update how things are going.

1 Like

Each of the clumping baddies could run a SphereCast (or use a second Collider with a larger radius), and if it hits other baddies, adjust direction. Not exactly sure how you should adjust it, or what happens when many of them do start clumping while trying to get away from each other, but it might be fun to experiment with and would be easy to implement.

1 Like

If you don’t use NavMesh because of procedural environment, theres NavMeshTools from Unity to bake a NavMesh during runtime (it’s really fast).
Using it would obviously solve your problem, as agents avoid other agent positions naturally.

But if you insist on not using it, you will have to use something else - physics would work if your enemies are rigidbodies. Character Controller (kind of a kinematic rigidbody controller with some limitations) should also work.

From there on, theres only complicated solutions where you have to manually navigate your agents away from each other, theres simple swarm behaviour, like trying to keep a specific minimum distance to each other. Iterating over multiple frames, the whole “swarm” will expand as much as possible (and needed → minDistance) in the given area, giving each agent the most possible space (if theres less space than needed for all agents to fit).

Next more complicated step would be some kind of traversal avoidance algorithm, that calculates the path of two or more agents and provides a route for them, so each one can get to their destination without touching the other agent. I’ve seen an approach with some kind of vector fields or flow maps, if I remember correctly - but thats better suitet for some kind of city simulation with hundreds of pedestrians.

So theres no limit to a complicated approach, if you really want to ^^
I’d keep it simple and use either NavMesh (highly suggested, as it is really fast, easy to use and offers enough tools to conquer each problem you may face, like climbing ladders) or Physics.

The whole strafing thing, really has nothing to do with collision avoidance. And I don’t think you can or should add it to collision avoidance. Collision avoidance should block strafing if there isn’t enough space, otherwise they should not interact.

1 Like

@John_Leorid I am actually using navmesh agents with update position and update rotation disabled to steer my npcs along their goal vector. Because navmesh agents do not avoid overlapping one another with these settings. I omitted that detail in the interest of keeping my question simpler. I probably shouldn’t have. Later on in the game I am hoping to take advantage of using the same character locomotion on my player as my npcs by including moving platforms or launching them in the air, as they are not meant to be bound to the ground. More massive enemies like those tanks that I grant enemy-to-enemy collision should push the smaller ones out of the way. That said, I am only a beginner. If these things are actually possible in navmesh then I’m all for switching.

I tried @seejayjames ’ suggestion and it worked, though my solution is really rough. But I can see how expanding on it could make interesting behaviors. Especially combined with something more complex like @Kurt-Dekker 's suggestion.

3 Likes