You know how in most forms of media (games, comics, movies, whatever) if a group of people gang up on the "hero" or player, they tend to attack one at a time?
It's a pretty common trope, but at least as far as games go it's also somewhat required for the player to have any chance against a large group of enemies.
That's a short gif from a prototype I'm working on. There are eight AI enemies attempting to attack at once - there are slight pauses here and there (each AI is set to take a short break after attacking) but when they decide to attack there's just too much going on.
DOOM (2016) uses an interesting method to restrict how chaotic having large numbers of enemies on-screen can be - each AI that wants to attack must request a "token" before it can do so. In this way, the designers can limit how many enemies can be attacking at once by limiting the number of tokens available. To make things even more dynamic, AI can also steal tokens from each other if they believe they have a better chance at attacking.
I've seen this technique simply referred to as using "combat tokens" but I've also seen it called having a "kung-fu circle" (technically a different method, but it is a similar idea).
I'm not entirely sure how widespread this technique is overall, but you can see evidence of at least similar techniques in other games. The Batman Arkham series from Rocksteady and WB Montreal very obviously does something to prevent every enemy from attacking at once - usually there are just two or three at most that can attack at the same time. I'm sure there are plenty of other similarly styled fighting games that use such a system as well (not to mention other genres).
I've been taking these ideas and slowly building a similar system for my prototype. It's fairly simple, basically just a way to force the AI to take turns attacking. But it results in much better behavior:
Now there are at most three enemies attacking any one time, and usually it's only one or two. So how does this work?
On every character that can be targeted by an AI, there's a "combat token source" component. This component manages handing out tokens to AI that want to attack.
When an AI asks to attack a character, it tells the token source a value and is given a spot in line in return. This value is set by a designer to represent how "big" an attack is - if it's something that should be the only attack happening then it should have a high value, if it's something that's fine to mix with lots of other attacks then it should have a low value.
The token source has a maximum value after which it stops letting AI attack. Once that threshold is hit, AI sit in a queue and are notified once enough other AI have finished with their tokens.
To make sure AIs aren't just attacking instantly one after the other, there's also a cooldown associated with token values. Whatever value was taken up by a token is made available over a short period after the token is released.
Here's what that looks like:
If the field names aren't clear enough, here's a more thorough description of what's going on:
Max Token Value: The maximum value the token source allows to be used at a time. Each token has a value, active token values added up cannot exceed the max token value.
Token Cooldown Multiplier: This is how fast value is made available.
Active Queue Size: Token activation happens on a first-come first-serve basis - only the token at the front of the queue will be considered for activation. The problem with this is if it has a particularly large value as the queue may get backed up. To combat this, a designer could tell the token source to instead look further ahead in the queue if the first AI has requested too much value. The active queue size is the number of tokens to look ahead.
Active Token Value: This is the total value of all active tokens.
Cooldown Token Value: This is the value that has been released from tokens, but hasn't been made available yet. This counts down at a constant rate (see Token Cooldown Multiplier) until it hits zero.
Conclusion
This system is in its early stages and still requires a lot of tuning, just like most of the AI I am prototyping. How well it will work (or how necessary it will end up being) for the style of game I'm creating still has yet to be seen. It was interesting to build, however, and should give some interesting knobs to turn in order to adjust difficulty down the road.