Sponsored By

Creating Natural AI

Problem: AI aimlessly wandering and unnatural Solution: Create tasks for the AI to complete around the level

Zachery McCurtain, Blogger

December 11, 2023

6 Min Read
Game Developer logo in a gray background | Game Developer

 In our game, we have lots of AI people walking around the level to be victims for the player to scare, make angry, etc. These victims are split into two types, guests and workers. Guests are there simply to be bullied by the player, while the workers are there to put a stop to the players' antics. At the moment we have a very uninspiring system of just having random points around the map that the AI would go to randomly with no cohesion, so often multiple would go to the same spot, and overall it was very much just aimless wandering. The solution I came up with for this problem was to create a task system where the AI would have tasks to travel to and complete around the level to bring more life to the scene.

The general idea was to have places of interest around the map for the AI (POI). These POIs would contain spots for the AI to occupy and those spots would contain tasks for them to complete. Then instead of wandering around from place to place randomly, the AI would go to a location and complete a task over time, then go to another location, complete another task, etc.

I started by creating a template for one of these POIs to work with. The first one I created was a dining table with chairs that the AI would go to eat. A POI consists of a parent object with some number of child objects that represent the spots the AI can occupy. In the dining table, the parent object is the table, and the spots are the chairs where the guests sit as well as one additional spot next to the table for the worker to stand at. The parent object has a POI script that holds references to the various worker and guest spots, as well as the types of tasks that the POI has. Each of the spots also holds 3 transforms, the transform of the visual object, one for the start position of the visual, and one for the position the visual needs to be to be used. This is so that when the AI comes to sit at the chairs the chair can be pulled out from under the table to be used, and pushed back when the AI leaves. Then there is a global POIManager that is a singleton that exists in the scene that holds a reference to all of the POIs in the scene and handles getting POIs and tasks to the AI.

For the tasks themselves, the idea was to create a flexible task system that allows for a large number of types of tasks. I did this by first creating a TaskTracker base class that keeps track of information such as the amount of progress made, any possible subtasks, has methods for getting important information such as the target location of the task or if the task has been completed, and has methods for affecting the task such as telling the task it is being started, stopped, or completed.

Next was to create a real subclass of this for the actual tasks the AI will use. At the moment there is only one type of task that I call occupant tasks. These are tasks held at POI’s where the AI goes to a POI Spot, stays there for some specified amount of time, and then the task is completed. To do this I started by creating an OccupantTaskOutline script that inherits from ScriptableObject to allow us to easily create variations of these tasks.

This scriptable object holds the necessary information to create a task, the amount of time the task takes to complete, who can complete the task, and the task it creates when it is completed, more details on that later. Then I created the subclass of TaskTracker called OccupantTaskTracker, which takes in an OccupantTaskOutline and a POISpot that is the location of the task. The class itself is very simple, it has a method to get the spot's location for the task so the AI can travel to the location. Once there the task tells the location to prepare for the AI to occupy it, in the case of the chairs this is the chairs moving out. Once the chairs are done moving the task tells the victim to occupy the spot which has the AI “sit down” in the chair. There is no animation currently so the AI just stands inside of the chairs. At this point the task is started which starts a timer that adds progress to the task, once the specified duration has elapsed the task is completed and the task tells the victim to vacate the spot, and the chair to return to its original position. Once the task is completed it tells the location to create a new task, this is where the output task from the task outline comes in. This new task is created like normal, but if it is a worker task it goes to the worker spots of the POI, and if it’s a guest task it goes to the guest spots of the POI. The purpose of this system is to allow both repeating tasks that will create another instance of themselves after being completed, and task series that create different tasks after they are completed in a series. For example, the dining task at the tables creates a cleaning task for the worker to complete, and the cleaning task will then in turn create a dining task for the guests.

Now is for the tasks to be created and acquired by the AI in the first place. As I said before the POI holds the types of tasks that are at that location. These are the task outlines, and when the game starts if it has an outline for a guest task it creates that task at all of the guest spots, and if it has a worker task it creates that task at all of the worker spots. Then when the AI needs a new task it asks the POI manager for a task to do which in turn looks through all the POIs and gets all of the valid tasks for that type of AI, and returns a random one. The AI then reserves that task so that no one else can take it and begins moving towards the target location. Once it completes the task it discards it and gets a new one repeating the whole process.

That is the overview of the entire system. This is an incredibly over-engineered way of accomplishing this functionality, but the point was to create a system that is easily expandable to other types of tasks. For example, I am currently working on creating another type of task where the AI will search for an object the player has left around the level, collect it, and return it to its original location. Because I did the heavy lifting in creating the foundation of the systems it is incredibly easy to create new tasks with very little technical debt.

Read more about:

Blogs
Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like