Basic AI or: How to do *stuff*
As those of you who keep up with our Discord may know, we’ve recently finished the first step towards implementing our AI framework. Good AI (or lack thereof) is one of those things that can make or break a game, yet many games neglect it. Designing a good AI takes a fair amount of thought, from gameplay requirements to technological (im-)possibilities. That’s why today I’d like to share some of the thought processes that went into our current design with you.
Setting the requirements
AoA is a very AI-driven game. Players will explore ruins filled with various types of enemies. From human raiders operating mounted guns and technicals, to alien wildlife and TV-headed robot zombies remote-controlled by a central processing unit there is a large variety of creatures that all behave in their own unique ways to provide diverse and unique challenges to the player. Not only that, but the player’s own survivors are largely AI-controlled too. While the player can give direct orders, for the most part survivors will look for work and satisfy needs autonomously. This sets a very high quality requirement for our AI: an enemy that bugs out and gets stuck on an empty soda can is a free kill, but if the player’s favorite subordinate gets stuck it’s frustration and a reloaded save.
At the same time writing AI for AoA is very difficult: not only do we have a large variety of potential actors, the game itself is a deep simulation with complex individual needs, combat and construction systems. Our actors have to be able to perform complex behaviors to interact with the game world in a large number of ways. While an enemy in a platformer might only need to go back and forth between two points, our survivors need to know how to eat, sleep, socialize, harvest and gather resources, build structures, equip and use arms and armor, etc. Since the world is entirely procedurally generated we can’t take any shortcuts through hardcoded scripting either. We can’t just set a particular encounter to always engage in a specific tactic when the player enters through the designated plot door. Players could approach from any angle, through doors, windows, by blowing up a wall and our AI has to react to it appropriately. As if that wasn’t enough, one of our major goals is a high degree of mod support, which means we have to keep our AI as open and accessible to modders as possible.
In our approach, we’ve divided the AI into two major types: a “manager” AI that determines what any given actor in a faction ought to be doing and a “task” AI that’s responsible for the actual execution. We’ll talk about the manager AI in a future post and focus on the task AI today.
A common programming paradigm is to take a complex problem and break it down into smaller problems until the solution becomes trivial. “Chop that tree” turns into “Go to position adjacent to that tree, then engage in chopping until it’s dead”, which in turn breaks down into things like “play animation x while damaging the tree for y points per second.”
As mentioned before, a lot of things can happen in a simulationist game like AoA. A player might designate a tree for chopping and a worker decides to chop it down and receives a chop task. On the way he could be attacked by wildlife and get injured. He could get tired or hungry. Or maybe an alien critter is using the tree as a shell like a hermit crab and responds to your assault by getting up and leaving. The task AI has to be robust enough to deal with all these situations dynamically as they arise. A common shortcut here is to simply program exceptions for each and every contingency. If the tree is a crab, do this. If you get hungry halfway do that. The problem with this approach is it requires a lot of handcrafting and thus can only account for situations the programmers explicitly foresaw. And in a game as dynamic as this, there will always be something you didn’t predict.
Putting on a Quality Act
Back when we were prototyping, we tried out a number of different approaches, from traditional behavior trees, GOAP and a number of other paradigms. What we ended up with for the task AI is a take on the behavior trees you see employed in many modern video games: each task is performed by following a Behavior, which is a collection of Acts.
Acts are atomic actions that immediately impact the game world. For example, ActGoTo moves an actor towards his target. ActChop chops the target down. ActBuild constructs an unfinished structure, and so on. Every Act simply defines the actions it performs in a fairly concise format, as well as the preconditions that must be met before it can be executed. For example, ActBuild and ActChop require being adjacent to the target while ActGoTo needs a clear path to the target.
Behaviors collect these Acts and go down the list one by one. The first Act is the one that leads to our ultimate objective. In the tree-cutting example that’s ActChop. But before you can chop you need to equip an axe from your inventory and go over to the tree. So the Behavior might look like this:
The Act lower in the list creates the preconditions for the Act above it. If you start chopping but ActChop reports it can no longer run because the tree got up and moved away from you, the Behavior will simply go down the list of Acts, find ActGoTo and run that to once again meet the conditions for Chop. By falling back to previous Acts, our Behaviors can automatically adapt to just about any situation, save ones that make task completion impossible, e.g. if the tree is destroyed by something else or moves to an unreachable location.
Since Acts only need to define a few actions and preconditions, it is very easy for a coder to implement new ones. Behaviors are even easier to modify, as they’re defined in XML files that anyone can edit. If a modder wanted to say, add an extra step to the chopping where the lumberjack spends two minutes calling the tree’s mother nasty names before beginning his work, it could be done with only basic knowledge in a few minutes of coding.
That concludes our brief overview of AoA’s task AI. If you have questions, suggestions or otherwise are interested in our work, feel free to leave a comment below or pop over to our Discord channel and hang out with us. We’re always happy to see new faces!