Aitu is now hosted on github. Aitu is an extract of the AI portion of Wooden Sphere. It uses a combination of Hierarchical Task Networks and a Utility system to allow AI characters to decide on a goal and create a plan to achieve their goal.
Tasks and plans
Tasks are the building blocks of this system. A Task is something that an AI character can do. They can have an Action enum which your code can switch on and perform some action. They can also have three std::function objects which get run at different times and can manipulate a WorldState object belonging to some character. Tasks have pre and post conditions which look at some WorldState property to determine their truthiness.
Plans are a list of tasks to be completed in sequential order. When creating a plan for some goal task, the planner looks at the preconditions for that task and see if any other tasks can satisfy those conditions. That is, for a goal task G it looks for any task T where T’s postconditions match G’s preconditions. Then if T has preconditions it looks for tasks that can satisfy those, etc. A plan then is a chain of tasks starting with something that has no other preconditions/can be started right away, and each successive task does something that allows the next task to be run, until finally reaching the goal task.
I chose this design because I wanted a flexible AI with the possibility of emergent gameplay. Since I never explicitly define dependencies between tasks but instead just expose their requirements, its easy to add in a new independent task which the planner can then pick up and use so long as it meets their requirements. No need to modify other tasks to make use of the new one, just define the task and the planner figures it out. And because of that you can get scenarios where the planner chose something unexpectely, since it just looks for anything that satisfies some condition. So some task that you added for one reason might find itself being used in a way you (or the player) didn’t predict.
Utility and considerations
So that covers what plans are and how they get created, but how does the AI choose a goal in the first place? Enter considerations. A Consideration is something that looks at some aspect of the character’s WorldState and gives it a score. Tasks can have multiple considerations associated with them, each one looking at one particular aspect of the world state. The task with the highest score becomes the goal. To calculate a consideration’s score you pick some function (linear, exponential, log etc), define the constants for that function (the ABC’s in ax^2 + bx + c) and select the input source that gets evaluated by that function. Currently you can pick any value in WorldState, as well as other sources such as the number of tasks run since some target task (to limit repeats). To make it simple to edit considerations I made the ConsiderationEditor for Unreal Editor.
So that wraps up the summary for Aitu, feel free to take a look at it on github.