In Part 2 (Retreating) we briefly touched on how Fire Imps in each other's line of sight were connected as a group, and that they would share alert levels. Today, I'm going to explain a little bit more about how this group movement actually works - and also introduce a new monster to the pack: The Skeleton Archer, with its Ranged Attacks. Combine Archers and Skeletons together and you have quite a challenging group of foes to deal with.

Group Chasing Behaviours in Detail

Let's break this group chasing behaviour down:

1. Detection Phase. For each frame (more specifically each iteration of the Behaviour Tree), the monster maintains 2 lists: threats (you), and friendlies (other skeletons) - based on line of sight. Entities that cannot be seen are not included in this list. The lists are cleared at the beginning of each iteration. In addition to these, breadcrumbs dropped by both threats and friendlies are also recorded. In future versions, things like visible furniture, entrances and exit doors, walls etc... will also be added. By this point, the monster now has a reasonable view of the world on this exact frame, and we use this information to help the AI determine what to do next.

2. Intention Phase. This is where the Behaviour Tree comes in handy - to aid in the decision making process. We'll not cover the specifics of the Behaviour Tree implementation here - the details are too numerous and will best fit in a future post. For an overview of Behaviour Trees, AIGameDev covers this particularly well: http://aigamedev.com/open/article/bt-overview/

So, conceptually speaking, our tree models a list of ordered priorities: A. Deal with threats, B. Follow alerted friendlies, C. Patrol. The first one we've already covered in Part 1: monsters chase after players in their line of sight, then breadcrumbs (smell trail), then to the target's last recorded location. If these actions fail - the next branch (priority) of the tree is parsed and the monster has a look at what the friendlies are up to. If his friends are alerted, this state is passed on and the monster becomes alerted also. He then proceeds to follow the alerted friend in the same way as in priority A (again line of sight, breadcrumbs, and last recorded location). If this fails also (there are no alerted friends visible), then we fall back to patrol (with best guess).

Priority B is particularly important - it allows the monsters to follow each other in a chain/queue-like fashion. As long as the leader of the pack is alerted and can see the enemy, this state and behaviour is propagated to other mobs down in the chain. There's some bugs and caveats to this method, one of them is that it's easy for the monsters to chase each other in a loop (or pairs), so there's some failsafe hackery code to stop this from happening. This is WIP, we plan on cleaning up this behaviour during production.

This is where the Behaviour Trees really shine. Because we've already defined a lot of the basic maneuvers described in Part 1, 2 & 3 as behaviour nodes we can now mix and match them to create new behaviours in our tree. A good example, is the Skeleton Archer. In our tree, there is a conditional node that switches between Chasing Behaviours (from Part 1) and Retreating Behaviours (Part 2). The condition is a whether the distance from the monster to the player is above or below 2 thresholds. To illustrate, we might have an Archer chase the player if it is 100 units away, but flee from the player if it is less than 50. The gap between the 50 and 100 threshold is to ensure we don't rubber band between the two states too quickly, so if the distance is 75 units, we remain in the current state.

So the resulting behaviour is that the Archer maintains a nice position away from you: never to engage in melee combat but always close enough to use his bow and arrow.

Conclusion

Apart from the new Archer behaviours, there's no special code to formulate groups here. It just so happens that a combination of melee type Skeletons (who are extremely aggressive and will chase you down as much as possible) and ranged Archers (who are cautious and will try to maintain a certain distance from you) results in quite effective emergent behaviour - it almost looks like they are working together.

More Ideas for Group AI

The above shows very basic, fundamental rules for group interaction. It's a work in progress - but we plan on bringing more complex manoeuvres in regards to group tactics. Depending on the monster type, critters will be able to do the following:

- Monsters won't attack if they are alone, and will flee instead. Some intelligent ones will flee towards a known group of other monsters. This results in luring, pulling the character towards a more dangerous area and then attacking again.
- Wounded skeletons prefer to escape while their friends are locked in battle - to go and find corpses, heal, and return to the fray later.
- Leaders - if a Skeleton King is in the area, his minions will tend to follow and do what he does.
- Flanking - if the player is currently engaged in battle, other monsters will attempt to flank you from either side or behind.

A plea for help for the next two days

As some of you may already know - my game TinyKeep is on Kickstarter and there are currently only 2 days left of funding to go! If you enjoy reading these kinds of technical articles, please consider pledging so I can continue active development of the game. Currently I have accrued over half the amount I need (~70%), but as Kickstarter is all or nothing I need to make the full £22k or I lose all my pledges so far. If I get funded, I plan to keep on releasing articles on all aspects of the game's development, including AI but also game mechanics, procedural generation, multiplayer networking, 3D graphics & animation, performance optimization, workflow, physics, collision detection - and everything in between! I don't claim to be an expert on all of these subejcts - this is just my journey in the world of game development, but I hope beginners out there will find inspiration from this. So please help if you can!