Dev Diary - MMORTS AI part 1

Posted by : at

Category : MMORTS   Dev-Diary

Over the last month I've gotten structures in and dealt with their resource costs. I thought would be useful to add in a little of the higher level AI to help round things out. High level AI is the "computer user"; the artificial intelligence needed to work with large groups of units the players don't control.

With structures and buildings I made I wanted each individual township to have its own defense. So if a keep was under the control of humans, human guards should spawn, patrol the town, and put up some resistance to invading forces. If the keep ownership switched, is rebuilt, and some time has pasted without an attack new units of the appropriate type should spawn and patrol. I also wanted a larger presence of a faction's control in the area; often called the "creep" in modern RTS games. That creep also needed organizational AI.

My first attempt was using a system I had put in place in my last project. I call it Behavior-Criteria-Action. The AI bot would have a set of behaviors. These wrapper objects are checked on an update interval and can be turned off if they don't apply. Each behavior has a set of criteria to check and when/if all criteria return true the behavior invokes its list of actions to perform some work. An example of this is a simple "When a unit is at location X, send unit Y to attack it." In this example the behavior has a single criteria ("is a unit at location X") and a single action ("give attack command to unit Y"). Criteria can be anything from checking the time, to checking if another behavior is active, to checking how many players are in the zone, and almost anything with units. Similarly actions can be nearly anything. In my last project I had nearly 20 criteria and more than that number of actions.

While a very robust system there is a major drawback: polling. Thus far I have attempted to never poll if it can be helped. Behavior-Criteria-Action system breaks that with the need to poll each behavior and each criteria to check the conditions. In our example above, to tell if a unit is at "location X" I would need to know where each unit is and if they match that location. I don't want polling like this and I don't think I need this robust of a system.

My second attempt is a lot more fun, only slightly more constraining, and more event driven; it is the Threat-Response. In this style I first grouped units under a parent object (threat processor). This would be a Keep, a squad, or whatever. I then gave units the power to send threat messages up to it's parent object. These messages come in a variety of flavors like "I saw an enemy", "I got hurt", and "I killed that enemy". The parent object then has some discretion with how to handle the message. Ultimately threats are either ignored, tallied in a dictionary, or produce commands sent down to the unit for the unit to act upon.

Parent objects can also have parent objects for larger coordination. There might be a scenario where a unit informs its squad that an enemy (or set of enemies) has been detected. The squad might then check if the threat is large enough to tell its parent, the main faction AI of that zone. (Determining how big the threat is plays well into "unit values" If the faction's zone AI feels the threat is large enough it may send orders (via a threat message) to another squad. Now both squads are alerted to the group of enemies and send their units attack orders.

This system is not without its own faults and challenges. The biggest challenge is how to create understand commands units should be given. For example, what happens if there are no threats? Do the units just stand around or should the squad give them commands to wander around, explore an area, patrol somewhere, or despawn? How does an AI deal with escalating threats from players, can it spawn more units to match what players can do?

That last question is an interesting one, and will lead to future posts. In a nutshell I am having each parent object have a minimum and maximum number of units to spawn or despawn as responses to threats. A squad might start with five warriors to roam around with. If all five are killed, then the next time it might respawn with seven, and after no threats are detected, for an hour, two of those warriors may despawn.

This pattern can be used for Squads controlled by a higher level parent threat processor. Squads have type to indicate their general behavior with types like "Scouting" to explore areas and not directly engage with enemies. "Attacker" squads can be created and to back up the scouting squads if a large enough enemy is found. "Siege" squads may be spawned if a set of structures are seen, and so forth.

In general I'm enjoying the Threat-Response pattern. I have several ways to expand it in the future and it is flexible enough to play around with.

Useful Links