An easy-to-use implementation of HTN (Hierarchical Task Networks) to control game characters in C#.
- Simple and performant, made for game development
- Expressive with minimal boilerplate
This library is parallel to Game Ready Goap, an implementation of GOAP.
Goal-Oriented Action Planning and Hierarchical Task Networks are both powerful choices for controlling NPCs. HTN defines a structured hierarchy of nested tasks that should be completed. GOAP defines a set of goals and a set of actions that can be combined to reach those goals.
HTN is simpler, faster and more predictable because the tasks use a predefined order. It's suitable for most game enemies which only have a limited set of actions. It's an implementation of a behaviour tree.
GOAP is more flexible and powerful because the actions can be combined in very complex ways. It's suitable for agents with lots of actions and strategies to consider, such as in Real-Time Strategy games.
This Reddit discussion provides more comparisons between GOAP, HTN and behaviour trees.
First, create an agent with initial states and a root task:
GoapAgent Agent = new() {
// These describe the current state of your agent (character).
States = new() {
...
},
// This is the root (compound) task your agent will run, changing its states.
Task = ...,
};
Then, finding a plan is easy:
Agent.FindPlan();
Executing plans is also easy:
Plan.Execute();
A farmer tends to his crops. He starts his day by farming to increase his crop health, which requires energy, then sleeps, increasing his energy. If he's too tired to farm, he sleeps instead.
public static readonly HtnAgent Agent = new() {
States = new() {
["Energy"] = 100,
["CropHealth"] = 0,
},
Task = new HtnSelectorTask("Root") {
Tasks = [
new HtnSequenceTask("CompleteDay") {
Tasks = [
new HtnPrimitiveTask("Farm") {
Effects = [
new HtnEffect() {
State = "CropHealth",
Operation = HtnOperation.IncreaseBy,
Value = 20,
},
new HtnEffect() {
State = "Energy",
Operation = HtnOperation.DecreaseBy,
Value = 30,
},
],
Requirements = [
new HtnCondition() {
State = "Energy",
Comparison = HtnComparison.GreaterThanOrEqualTo,
Value = 30,
},
],
},
new HtnPrimitiveTask("Sleep") {
Effects = [
new HtnEffect() {
State = "Energy",
Operation = HtnOperation.IncreaseBy,
Value = 5,
},
],
},
],
},
new HtnPrimitiveTask("Sleep") {
Effects = [
new HtnEffect() {
State = "Energy",
Operation = HtnOperation.IncreaseBy,
Value = 5,
},
],
},
],
},
};
Farmer.FindPlan();
We get 2 actions which completes our task by selecting the CompleteDay
task:
Action | Energy | Crop Health |
---|---|---|
- | 100 | 0 |
Farm | 70 | 20 |
Sleep | 75 | 20 |
If we set Energy
to 20 instead of 100, we get 1 action which completes our task by selecting the Sleep
task:
Action | Energy | Crop Health |
---|---|---|
- | 20 | 0 |
Sleep | 25 | 0 |
- This Is Vini for explaining the HTN algorithm.
- Fluid HTN for explaining the difference between selector and sequencer compound tasks.