We are making game using Entity Systems. And we with my colleague have different opinions about what approach is better when doing AI.

Basically, he thinks that everything should be a system, where I'm not.

That is his way:

Systems:
- Sensor System (look for a target)
- Pathfinding System (find a path to a target which will be colliding between agents with high probability)
- Attack System (attack target if in attack range)
- Movement System (advance path to target, resolve colliding if can't advance)

There is my proposal:

Systems:
- Attack System (find a target with hp > 0, write to Target component and attack if in range)
- Movement System (find a path to target (if there isnt already) and advance)
Utility classes:
- Sensor
- Pathfinding

There is problem with first approach. For example, 10 units all choosed one target and attacked it (simly because it was closer). But in reality 3 units are sufficient to kill that target in an instant. So, why other 7 should attack this target too? When they choosed their target they doesn't known yet that 3 unit would suffice. They know now that target hp <= 0 but they can't choose another, because Sensor System finished his work already. If we want to fix it then problem will be in unreasonable complexity of Sensor system.
Where in latter approach we simply wouldn't select target if hp already <= 0.

Similarly, in first approach pathfinding will find paths which are colliding between them. When one unit taken grid cell another can't take it. That means he must forget his path. But he can't build a new, because Pathfinding system already finished his work. So, he advances one cell in direction of target. In latter approach, we will build path in respect to new positions of units.

Maybe there are another problems in both approaches which we couldn't foresee. So, please say something if you know.

Which way are better (both clear code and good AI)? Maybe both are wrong then please advice what is right way to make it.

You most likely have a system for Attack/Movement already, considering your AI isn't going to be the only one Moving/Attacking so don't create new ones just for AI. The mecanisms are the same for playing characters or AI players.

Every AI entity should be responsible for its own decisions. With that in mind, I'd add an AI component to AI entities and maybe a system to handle that component (it depends if your engine has behavior on components or only in systems). That component/system pair is responsible for making decisions and emitting commands.

Pathfinding is really a global resource that is typically accessed in the same way by every moving entity. In that regard, I'd be on your side and make it a helper class/function. The idea is that systems should be used to update components, not provide arbitrary functionality unrelated to components.

As for sensors, I also disagree with making a system for them unless you absolutely have to limit the amount of information available to your AI artificially. For example, if actual players can write AIs for your game, you probably want to set what their agent knows or not so a system to achieve that and prepare a context or a component would be justified. In your case though, you should just query the world around you for the information you need.

In short:

Add a component/system for AI and make it responsible for making decisions and emitting commands by leveraging your already (hopefully) existing movement and attack mecanics

Make pathfinding a globally accessible resource, not a system

Don't abstract understanding your agent's surroundings with a "sensory" layer, just plain old query the world directly

As for your friend, he means well but sometimes we have to be reminded of pragmatism. Not everything has to fit the paradigm perfectly :)

> Add a component/system for AI. But what if we should be able to change decision midway? For example, 4 units decided to attack same target. AI system finished work. Then Attack system perform attack for each unit sequentially. Third unit killed target. Forth unit should choose new, but new target is far away, that means he really should move instead of attack. How to handle that?
–
bobbyJul 26 '13 at 14:19

1

@bobby There are several ways to handle your first concern. A lot of games will just ignore it (for example, the last bullet from one of the characters will be in the air when the unit dies). Think about it, would a soldier stop firing at an enemy assuming his buddy will kill him first? Your agent will move on the next frame anyways and frames are really short so the delay is acceptable in 99% of cases.
–
pwnyJul 26 '13 at 14:33

1

@bobby I can't really answer in much detail regarding your second concern without seeing your code but I'll do my best to describe the general idea. Your AI system should perform all calculations required to initiate an action then do so. For example, evaluate the entity's state and environment, decide where it wants to move and initiate the move action (maybe putting a movement command in the command queue). For attacking, it could be selecting a target and going into "attack mode". Your system responsible for actually computing combat takes care of the rest.
–
pwnyJul 26 '13 at 14:37

1

@bobby That shouldn't happen because your pathfinding should handle it and return a path that doesn't produce collisions. If it does happen for some reason, compute a different path for the entity that found a colliding path.
–
pwnyJul 26 '13 at 14:52

1

@bobby Maybe, but the calculated path can take into account the paths computed for other units. You can also recompute paths regularly or do so when you detect an eventual collision. At this point it's really dependant on your particular engine and game.
–
pwnyJul 26 '13 at 15:05