Chapter 7: Task Management
In Chapter 6: Navigation System, we learned how NPCs find their way around the game world. But what happens when an NPC needs to perform a complex series of actions? For example, a guard might need to patrol an area, investigate suspicious noises, and then return to patrolling. How do we organize these behaviors into meaningful sequences? That’s where the Task Management system comes in!
What is Task Management?
Think of Task Management as your NPC’s personal to-do list organizer. Just like how you might write down a list of chores (do laundry, wash dishes, take out trash) in order of importance, the Task Management system helps NPCs organize their behaviors in a logical sequence.
For example, an enemy soldier might need to:
- Go to the player’s last known position
- Search the area
- Return to patrol if the player isn’t found
Without Task Management, programming these sequences would be complicated and difficult to maintain. The Task Management system makes this process much simpler by allowing us to create “tasks” that contain multiple behaviors, prioritize them, and execute them in order.
Key Components of Task Management
Let’s break down the main elements of the Task Management system:
1. Tasks: The To-Do Items
A Task is like a single item on a to-do list. It represents a specific goal the NPC wants to accomplish, which might require multiple steps:
// Creating a simple patrol task
Task patrolTask = behaviourManager.AddTask(1.0f); // Priority 1.0
This code creates a new task with a priority of 1.0. The priority determines how important the task is - higher priority tasks will interrupt lower priority ones.
2. Behaviors: The Task Steps
Each task consists of one or more Behaviors - the individual steps needed to complete the task:
// Adding behaviors to our patrol task
Vector3 pointA = new Vector3(10, 0, 0);
Vector3 pointB = new Vector3(-10, 0, 0);
// Step 1: Go to point A
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Go, 5, TargetType.Point, pointA));
// Step 2: Wait for 3 seconds
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Wait, 3));
// Step 3: Go to point B
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Go, 5, TargetType.Point, pointB));
// Step 4: Wait for 3 seconds
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Wait, 3));
This code adds four behaviors to our patrol task, creating a sequence where the NPC will:
- Go to point A
- Wait for 3 seconds
- Go to point B
- Wait for 3 seconds
After all behaviors are completed, the task will be removed, and the NPC will move on to the next highest-priority task.
3. Task Queue: The Priority List
The Task Management system maintains a queue of pending tasks, sorted by priority:
// These tasks will be executed in order of priority (highest first)
// Patrol task (lower priority)
Task patrolTask = behaviourManager.AddTask(1.0f);
// Search task (medium priority)
Task searchTask = behaviourManager.AddTask(2.0f);
// Attack task (highest priority)
Task attackTask = behaviourManager.AddTask(3.0f);
In this example, the attack task (priority 3.0) will be executed first, then the search task (priority 2.0), and finally the patrol task (priority 1.0).
How to Use Task Management
Now let’s see how to use Task Management to create a guard NPC that patrols an area and responds to intruders:
Step 1: Creating a Basic Patrol Task
// Get the NPC's behavior manager
NpcController guardController = GetComponent<NpcController>();
BehaviourManager manager = guardController.manager;
// Create a low-priority patrol task
Task patrolTask = manager.AddTask(1.0f);
// Define patrol points
Vector3 pointA = new Vector3(10, 0, 0);
Vector3 pointB = new Vector3(-10, 0, 0);
// Add patrol behaviors
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Go, 10, TargetType.Point, pointA));
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Wait, 3));
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Go, 10, TargetType.Point, pointB));
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Wait, 3));
This code creates a patrol task with four behaviors. Since it has a low priority (1.0), it will be interrupted by more urgent tasks.
Step 2: Creating an Investigate Task
When a suspicious noise is heard, we want the guard to investigate:
// When a suspicious noise is detected
void OnSuspiciousNoise(Vector3 noisePosition)
{
// Create a medium-priority investigate task
Task investigateTask = manager.AddTask(2.0f);
// Go to the noise source
investigateTask.AddBehaviour(new Behaviour(
BehaviourType.Go,
10,
TargetType.Point,
noisePosition
));
// Look around
investigateTask.AddBehaviour(new Behaviour(
BehaviourType.Wait,
5
));
// After investigation, the NPC will return to patrolling
}
Since this investigate task has a higher priority (2.0) than the patrol task (1.0), it will interrupt patrolling. After the investigate task is completed, the NPC will automatically return to the patrol task.
Step 3: Creating an Attack Task
If an intruder is spotted, we want the guard to attack:
// When an intruder is spotted
void OnIntruderSpotted(UniObjectData intruder)
{
// Create a high-priority attack task
Task attackTask = manager.AddTask(3.0f);
// Move to the intruder
attackTask.AddBehaviour(new Behaviour(
BehaviourType.Go,
5,
TargetType.Character,
intruder
));
// Attack the intruder
attackTask.AddBehaviour(new Behaviour(
BehaviourType.Attack,
10,
TargetType.Character,
intruder
));
}
This attack task has the highest priority (3.0), so it will interrupt both investigating (2.0) and patrolling (1.0). After the attack is completed (or if the intruder escapes), the NPC will move on to the next highest-priority task.
How Task Management Works Internally
Let’s see what happens inside the Task Management system when tasks are created and executed:
sequenceDiagram
participant Game as Game Update
participant BM as Behaviour Manager
participant TQ as Task Queue
participant CT as Current Task
participant NPC as NPC Controller
Game->>BM: Update()
alt No Current Task
BM->>TQ: Get highest priority task
TQ-->>BM: Return task
BM->>CT: Set as current task
CT->>CT: Start first behavior
CT-->>NPC: Execute behavior
else Has Current Task
BM->>CT: Continue current behavior
CT->>CT: Check if behavior completed
alt Behavior Completed
CT->>CT: Move to next behavior
alt No more behaviors in task
CT-->>BM: Task completed
BM->>CT: Clear current task
else Has more behaviors
CT->>CT: Start next behavior
CT-->>NPC: Execute next behavior
end
end
end
This diagram shows the process:
- Every game update, the Behaviour Manager checks if it has a current task
- If not, it gets the highest priority task from the queue
- It starts the first behavior in that task
- When a behavior completes, it moves to the next behavior in the task
- When all behaviors in a task are completed, it moves to the next highest priority task
Let’s look at the key code that makes this happen:
public void Update()
{
// If we don't have a current task, get the next one
if (task == null)
{
GetNextTask();
// If still no task, create a "spare time" task
if (task == null)
{
CreateSpareTimeTask();
}
}
else if (task.behaviour == null)
{
// Current task has no behaviors, clear it
task = null;
}
// Update the current behavior
task?.behaviour?.CheckEndTime();
task?.behaviour?.CheckCompletion();
}
This method runs every game update and is the heart of the Task Management system. It:
- Checks if there’s a current task
- If not, gets the next highest-priority task
- If there are no tasks, creates a “spare time” task (idle behaviors)
- Checks if the current behavior is complete
- If so, moves to the next behavior in the task
Handling Task Completion and Transitions
When a behavior completes, the system automatically moves to the next behavior in the task:
public void GetNextBehaviour()
{
// Move to the next behavior in the list
index++;
// If there are more behaviors, start the next one
if (index < behaviours.Count)
{
behaviour = behaviours[index];
behaviour.Reset();
}
else
{
// No more behaviors, task is complete
behaviour = null;
}
// Notify the system that the behavior has changed
manager.OnBehaviourChanged();
}
This method is called when a behavior completes. It moves to the next behavior in the task, or marks the task as complete if there are no more behaviors.
The Spare Time Task Feature
One clever feature of the Task Management system is the automatic creation of “spare time” tasks when the NPC has nothing important to do:
void CreateSpareTimeTask()
{
// Create a low-priority spare time task
task = AddTask(0.25f);
// Randomly choose one of several idle behaviors
switch (Random.Range(0, 5))
{
case 0: // Look at something random
UniObjectData target = controller.GetRandomTarget();
task.AddBehaviour(new Behaviour(
BehaviourType.LookAt,
Random.Range(1, 3),
TargetType.Character,
target));
break;
case 1: // Just wait a bit
task.AddBehaviour(new Behaviour(
BehaviourType.Wait,
Random.Range(0, 1)));
break;
case 2: // Wander around
(bool isOk, Vector3 position) = controller.GetRandomPosition();
if (isOk)
{
task.AddBehaviour(new Behaviour(
BehaviourType.HangAround,
Random.Range(2, 4),
TargetType.Point,
position));
}
break;
}
}
This code creates random idle behaviors for NPCs when they have nothing important to do. It’s like how people might check their phone or look around when waiting in line - it makes NPCs seem more alive and realistic.
Practical Example: Creating a Complete Guard AI
Let’s put everything together to create a complete guard AI with multiple tasks:
void CreateCompleteGuardAI()
{
// Create the guard GameObject
GameObject guardObject = new GameObject("Guard");
NpcController controller = guardObject.AddComponent<NpcController>();
// Initialize the controller
controller.Init(npcInstance, characterInstance);
// Get the behaviour manager
BehaviourManager manager = controller.manager;
// 1. Create patrol task (lowest priority)
Task patrolTask = manager.AddTask(1.0f);
Vector3 pointA = new Vector3(10, 0, 0);
Vector3 pointB = new Vector3(-10, 0, 0);
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Go, 10, TargetType.Point, pointA));
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Wait, 3));
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Go, 10, TargetType.Point, pointB));
patrolTask.AddBehaviour(new Behaviour(
BehaviourType.Wait, 3));
// 2. Set up target detection
controller.npc.GetPropertyByName("automaticTargeting").Data.b = true;
controller.npc.GetPropertyByName("targetsTag").Data.s = "Player";
}
This code creates a guard NPC that will patrol between two points. When it detects a player (using the Target System), other systems like the Factor Monitoring System can create higher-priority tasks like attacking or investigating.
Integration with Other Systems
The Task Management system works closely with other AI systems:
Connection to the Behaviour System
The Task Management system uses the Behaviour System to define and execute individual behaviors:
// Creating a behavior using the Behaviour System
Behaviour goToBehavior = new Behaviour(
BehaviourType.Go, // Behavior type
5.0f, // Duration (seconds)
TargetType.Point, // Target type
targetPosition // Target data
);
// Adding this behavior to a task
patrolTask.AddBehaviour(goToBehavior);
The Behaviour System provides the building blocks (individual behaviors), while the Task Management system organizes these blocks into meaningful sequences.
Connection to the NPC Controller
When tasks and behaviors are executed, the NPC Controller handles the actual implementation:
private void Manager_OnBehaviourChangedEvent(Behaviour behaviour)
{
if (behaviour == null) return;
// The NPC Controller implements different behaviors
switch (behaviour.type)
{
case BehaviourType.Go:
StartNavigation();
break;
case BehaviourType.Wait:
StopNavigation();
break;
case BehaviourType.Attack:
// Trigger attack animation/logic
break;
}
}
The Task Management system decides what to do, while the NPC Controller handles how to do it.
Connection to the Factor Monitoring System
The Factor Monitoring System can create tasks based on changes in the NPC’s state:
private void Database_NewTrigger(BehaviourType type)
{
switch (type)
{
case BehaviourType.Escape:
// When health is low, create a high-priority escape task
(bool isOk, Vector3 position) = GetRandomPosition();
if (isOk)
{
manager.AddTask(3).AddBehaviour(new Behaviour(
BehaviourType.Escape,
Random.Range(2, 6),
TargetType.Point,
position));
}
break;
}
}
This creates a seamless integration where changes in factors (like health) can automatically create appropriate tasks.
Best Practices for Using Task Management
-
Use Appropriate Priorities: Higher priority numbers mean more important tasks. Use a consistent scale (e.g., 1-5) to make your priorities clear.
-
Keep Tasks Focused: Each task should represent a single goal or intention. Don’t try to cram too many unrelated behaviors into one task.
-
Use Task Management for Complex Sequences: For simple behaviors, you might not need tasks. But for sequences of 2+ behaviors, tasks provide better organization.
-
Clean Up Completed Tasks: The system automatically removes completed tasks, but you might need to manually cancel tasks that become irrelevant.
-
Balance Task Complexity: Very long tasks (many behaviors) might make NPCs seem unresponsive to new events, as they’ll complete the entire task before moving on.
Conclusion
The Task Management system provides a powerful way to organize NPC behaviors into meaningful, prioritized sequences. By combining multiple behaviors into tasks and managing these tasks based on priority, we create NPCs that can handle complex goals while still responding appropriately to changing situations.
This system works hand-in-hand with the other systems we’ve learned about, creating NPCs that can:
- Follow complex sequences of behaviors (Task Management)
- Execute individual behaviors effectively (Behaviour System)
- Respond to changing internal conditions (Factor Monitoring System)
- Navigate to important locations (Navigation System)
- Find and interact with relevant objects (Target System)
- Display unique personality traits (NPC Personality System)
In the next chapter, Reactive Behavior Triggers, we’ll learn how to make NPCs respond immediately to specific events in the game world, creating even more dynamic and responsive AI characters.
Generated by AI Codebase Knowledge Builder