Summary
Goal-Oriented Action Planning (GOAP) is a deliberative AI architecture in which an agent chooses a goal, searches for a sequence of actions that could achieve it, and then executes that plan while monitoring whether replanning is needed. It is most useful when the designer wants emergent multi-step problem solving rather than only reactive branch selection. (Millington, Artificial Intelligence for Games, see source-artificial-intelligence-for-games)
Key ideas
- World state: facts currently believed true.
- Goal: a desired future state.
- Action: has preconditions and effects.
- Planner: searches for a valid action chain.
- Replanning: if the world changes enough, the plan may need to be rebuilt.
Implementation
public sealed class GoapAction
{
public string Name;
public int Cost;
public HashSet<string> Preconditions = new();
public HashSet<string> Effects = new();
}Minimal planning loop:
- Read current world state.
- Pick the most important goal.
- Search for actions whose effects can satisfy the goal.
- Execute the first action in the plan.
- Re-evaluate if the world state changes.
In Unity, keep the planner separate from movement. The planner should decide what sequence to pursue; steering or navigation decides how to move there.
How the planner searches
Orkin describes the planner in F.E.A.R. as STRIPS-style goals and actions with a cost per action, searched with A*: “In the case of planning, the nodes are states of the world, and we are searching to find a path to the goal state. The edges connecting different states of the world are the actions” (Orkin, “Three States and a Plan: The A.I. of F.E.A.R.”, GDC 2006). Costs let the designer rank alternatives: in Orkin’s example a cheap OrderPizza action is preferred, and a costly BakePie action is the fallback when pizza’s preconditions cannot be met. The same A* you use for pathfinding-algorithms does the work; only the graph changes.
Orkin lists cost per action as the first of four changes to academic STRIPS; the other three are preconditions and effects stored as a fixed world-state array of variables (for example TargetDead and WeaponLoaded), procedural preconditions (code checks such as “is there a path to safety?”, too expensive to keep in the world state), and procedural effects (an action takes time to carry out, so its effects are not instant) (Orkin, “Three States and a Plan”).
Worked example: a GOAP woodcutter
A runnable Unity 6 example, about 265 lines of plain C#, lives in code/unity-csharp/game-ai/goap/ (scene setup and things to try are in its README):
- WorldState.cs — named
boolfacts; a missing fact counts asfalse - GoapAction.cs — name, cost, preconditions, effects, plus a target and duration for execution
- GoapPlanner.cs — A* over world states
- WorkerAgent.cs — defines the actions, executes the plan and replans
The worker has one goal, WoodDelivered, and four actions:
| Action | Cost | Needs | Gives |
|---|---|---|---|
GetAxe | 2 | AxeOnRack, not HasAxe | HasAxe, not AxeOnRack |
ChopWood | 4 | HasAxe, not HasWood | HasWood |
GatherBranches | 8 | not HasWood | HasWood |
DeliverWood | 1 | HasWood | WoodDelivered, not HasWood |
Code walkthrough
WorldState stores facts in a Dictionary<string, bool> rather than the HashSet<string> sketch above, because a precondition sometimes needs a fact to be false (you can only chop wood when your hands are empty). Satisfies() checks a set of conditions, CountUnmet() gives the planner its heuristic, and Key() turns a state into a string so the planner can recognise states it has already reached.
GoapAction is data. The fluent Needs() and Gives() calls make each action read like a rule, and ApplyTo() returns a copy of a world state with the effects applied, so planning never changes the real world.
GoapPlanner.Plan() is A*. Each open node holds a world state, the action that produced it, its cost so far (g) and f = g + h, where h is the number of goal facts still unmet. It repeatedly expands the cheapest node, tries every action whose preconditions hold, and stops when a state satisfies the goal; walking back through the parents gives the plan. From the start state {AxeOnRack} there are two plans: GetAxe > ChopWood > DeliverWood (cost 7) and GatherBranches > DeliverWood (cost 9). The planner returns the first.
WorkerAgent executes one action at a time: walk to the action’s target, work there for its duration, and only then apply the effects to the live world state. Every frame it re-checks the current action’s preconditions. If you choose Break Axe from the component’s menu while the worker is heading for the tree, ChopWood no longer holds, so the worker replans; with the axe rack empty, the only plan left is the costlier GatherBranches route. This mirrors, on a small scale, the replanning Orkin describes, where an enemy that cannot open a held door replans to kick it, then replans again to dive through a window (Orkin, “Three States and a Plan”).
What to change first
| Change | Expected effect |
|---|---|
Cost of GatherBranches below 6 | the worker ignores the axe and gathers branches from the start |
| Break Axe while chopping | replans to GatherBranches > DeliverWood |
| Restock Axe Rack | the next plan (after the current one ends) uses the axe again |
| Drop Wood on the way to the storehouse | DeliverWood fails and the worker fetches more wood |
Remove GatherBranches from the list, then break the axe | the planner returns no plan, and the worker retries every second |
Trade-offs
- Stronger than behaviour-trees when long multi-step reasoning matters.
- More expensive and less predictable than an FSM or BT.
- It does not replace a state machine so much as sit above one: in F.E.A.R. the character FSM had only three states,
Goto,AnimateandUseSmartObject, and plan actions worked by setting the FSM’s state and parameters (Orkin, “Three States and a Plan”; see ai-state-machine-pattern). - Requires careful authoring of preconditions and effects or the search space becomes noisy.
Examples
- Classic GOAP examples include agents deciding whether to find a weapon, secure cover, flank, or heal before attacking.
- F.E.A.R. (Monolith, 2005) is the usual reference point. Orkin names the planner Goal-Oriented Action Planning and gives three benefits: goals decoupled from actions, so different characters can satisfy the same goal with their own action sets; simple behaviours layering into complex ones; and dynamic problem solving through replanning. He reports that a new flying drone enemy was built late in development by combining goals and actions from existing characters (Orkin, “Three States and a Plan: The A.I. of F.E.A.R.”, GDC 2006).
- Buckland’s goal-driven behaviour is not identical to formal GOAP, but it is a useful stepping stone because it introduces desirability-driven goal arbitration and queued subgoals (Buckland, Programming Game AI by Example, see source-programming-game-ai-by-example).
Practice
Turn the woodcutter into a soldier. Copy WorldState.cs, GoapAction.cs and GoapPlanner.cs unchanged, and write a SoldierAgent based on WorkerAgent with:
- facts
WeaponOnRack,HasWeapon,WeaponLoaded,TargetDead - actions
PickUpWeapon(cost 2),Reload(cost 1),Shoot(cost 1, needsHasWeaponandWeaponLoaded), and a fallbackMelee(cost 6, no weapon needed) - the goal
TargetDead - a context-menu item “Jam Weapon” that sets
WeaponLoadedtofalse
Before pressing Play, write down the plan you expect.
Success test:
- the first logged plan is
PickUpWeapon > Reload > Shoot - choosing “Jam Weapon” on the way to the target triggers a “no longer possible” log and a new plan
- with the weapon rack empty from the start, the plan is
Melee - you did not edit the planner to get any of this
Extension:
- add a procedural precondition: give
GoapActionaFunc<bool>that the planner also checks, and use it soShootis only allowed when aPhysics2D.Raycastfrom the soldier to the target (with a layer mask that skips the soldier itself) hits the target first, not a wall
Self-test
- In a GOAP planner that uses A*, what are the nodes and what are the edges?
- Why does the woodcutter fetch the axe on its first trip instead of gathering branches?
- Why does
GoapAction.ApplyTo()return a newWorldStateinstead of changing the one it is given? - When does
WorkerAgentdecide to replan? - In F.E.A.R., how did the planner relate to the character’s state machine?
- What is a procedural precondition, and why would you use one?
Answers
- The nodes are world states; the edges are actions whose preconditions hold in a state, leading to the state their effects produce.
- The axe route costs 2 + 4 + 1 = 7 and the branch route costs 8 + 1 = 9; A* returns the cheapest plan.
- Planning explores many possible futures, so it must work on copies; the real world state changes only when an action has actually been carried out.
- When the current action’s preconditions no longer hold in the live world state, and whenever a plan has finished.
- The planner chose actions, and each action set one of only three FSM states (
Goto,Animate,UseSmartObject) with parameters such as a destination. - A precondition checked by code at planning time, such as “is there a path to safety?”, for facts that are too expensive or too numerous to keep in the world state.
Related
game-ai-agent-design · overview-agent-ai-route · behaviour-trees-vs-goap · behaviour-trees · ai-state-machine-pattern · pathfinding-algorithms · steering-behaviours · utility-ai · source-artificial-intelligence-for-games