Summary of "GOAP Enemy AI FULL IMPLEMENTATION | AI Series 50 | Unity Tutorial"
Overview
This video demonstrates a full implementation of an enemy AI (“llama”) using a GOAP (Goal‑Oriented Action Planning) system for Unity (Crash Conagen’s free Apache‑2.0 implementation). The finished AI supports three goals — Wander, Kill Player, and Eat — with actions including wandering, melee attack, ranged spit, and eating. The system uses sensors and world keys to inform planning and choose actions based on costs, preconditions/effects, and in‑range thresholds.
The tutorial covers architecture and coding patterns (factory & builder), ScriptableObject configuration, dependency injection for non‑Mono classes, movement via NavMeshAgent, animation integration, object pooling for projectiles, and debugging with a GOAP node viewer.
Key concepts
-
GOAP basics
- Goals represent desired world states.
- Actions have preconditions, effects, and costs; the planner builds a sequence of actions to reach a goal.
- Sensors update the planner’s world state / agent memory.
- Targets and world keys identify objects and variables the planner uses.
-
Separation of concerns
- Actions are discrete capabilities.
- Sensors supply the world state.
- An
AgentBehavioracts as the GOAP “agent interface” (analogous toNavMeshAgentfor navigation).
-
Action lifecycle
- Created →
Start(enter) →Perform(each frame while running) →End(on finish).
- Created →
-
Sensor types
LocalTargetSensorBase: returns aTarget.LocalWorldSensorBase: returns a value (e.g., hunger).- Local sensors are per‑agent; global sensors represent shared state.
-
Data-driven configuration
- Use ScriptableObjects for tunable data (attack config, wander config, bio/balance config).
- Use dependency injection (GOP config initializer &
IInjectable) so non‑Mono classes can receive config objects.
-
Planner tuning
- “In‑range” and “base cost” values strongly affect when the planner reevaluates and which action it picks.
- Example: set a large in‑range for melee planning so the agent will start chasing before reaching melee range; set a small in‑range for eating so the agent reaches the food first.
Step‑by‑step methodology
-
Install GOAP package
- Add the Unity package by Git URL (requires Git installed) and import samples.
-
Project organization
- Create script folders:
Actions,Behaviors,Factories,Goals,Sensors,Targets,WorldKeys,Config. - Keep consistent folder structure (GOP subfolder and subfolders per type).
- Create script folders:
-
Create core GOAP classes
- Goals: extend
GoalBaseto createWanderGoal,KillPlayerGoal,EatGoal. - Targets: extend
TargetKeyBaseto createWanderTarget,PlayerTarget,GrassTarget. - WorldKeys: extend
WorldKeyBaseto create keys likeIsWandering,PlayerHealth,Hunger,Saliva,PlayerDistance.
- Goals: extend
-
Sensors
WanderTargetSensor:LocalTargetSensorBase— pick a random navigable point (useNavMesh.SamplePosition; retry attempts) using wander config.PlayerTargetSensor:LocalTargetSensorBaseor event‑driven collider sensor — find player viaOverlapSphereor trigger.GrassTargetSensor:LocalTargetSensorBase—OverlapSphere, sort results by distance, return nearest grass.HungerSensor:LocalWorldSensorBase— read hunger value fromHungerBehavior(Mathf.FloorToInt).SalivaSensor:LocalWorldSensorBase— read saliva fromSalivaBehavior.PlayerDistanceSensor:LocalWorldSensorBase— return distance to player when in sensor radius (inject attack config).- Prefer event‑driven enter/exit sensors (trigger collider) to avoid expensive per‑frame overlaps.
-
Actions (extend
ActionBase)- Define a common action data class implementing
IActionData: includesITargetand a timer. WanderAction- Data: timer controlled by
WanderConfig(injected). Start: set timer to random range from config.Perform: decrement timer; return Continue until timer ≤ 0 then Stop.- Movement handled by shared
AgentMoveBehavior.
- Data: timer controlled by
MeleeAttackAction- Data: target, timer, animator references (use
[GComponent]attribute to auto‑getAnimator). - Inject
AttackConfigfor melee radius, cost, delay, masks. Perform: check target distance ≤ melee radius, animate/look at target, manage attack timing.
- Data: target, timer, animator references (use
SpitAction(ranged)- Extends attack data, includes refs to
SpitBehaviorandSalivaBehavior([GComponent]). - Use object pool to spawn projectile prefab from
AttackConfig. - Register to
SpitBehavioranimation event (spawn trigger) so action receives spawn timing. Start: subtract saliva (cost) and register event handler;Performhandles look/animate;Endunregisters.
- Extends attack data, includes refs to
EatAction- Data includes
HungerBehavior. Start/Perform: stop hunger increment (disableHungerBehavior), animate eating, restore saliva and lower hunger over time using BioScience config rates.Endre‑enable hunger behavior.
- Data includes
- Define a common action data class implementing
-
Behaviors (MonoBehaviours)
AgentMoveBehavior- Requires
NavMeshAgent,Animator,AgentBehavior. - Listens to
AgentBehaviortarget changes, setsNavMeshAgent.destination. - Uses throttle (min move distance) and animates a walk boolean based on velocity.
- Requires
AgentBehavior- Uses GOAP runner components to interact with GOAP system (current target events, goal setting).
LlamaBrain- Sets current goal on start (
WanderGoal) and responds to player sensor enter/exit to setKillPlayerorWander/Eatdepending on hunger.
- Sets current goal on start (
SpitBehavior- Receives animation event (
BeginSpit) and raises a spawn event that actions subscribe to.
- Receives animation event (
HungerBehavior&SalivaBehavior- Hold and update hunger/saliva values each frame (increment/decrement based on BioScience config). Saliva decays; eating restores it.
PlayerSensorMonoBehaviour- Trigger collider that fires player enter/exit events. Attach as child to enemy and set proper layer & isTrigger = true.
-
Factory & Builder (
GOPSetConfigFactory)- Implement a factory extending
GOPSetFactoryBasewithCreate()to build a GOP set for the agent type. - Use a builder pattern:
builder.AddGoal(goalType, conditionWorldKey, comparison)builder.AddAction(actionType).SetTarget(TargetKey).AddEffect(WorldKey, effectValue).SetBaseCost(...).SetInRange(...)builder.AddSensor(sensorType).SetTarget(TargetKey)
- Link goals, actions, sensors, effects, costs, and in‑range thresholds in the factory.
- Implement a factory extending
-
Dependency injection for configs and non‑Mono classes
- Create a
DependencyInjectorclass extendingGOPConfigInitializerBaseand implement injector interface so the GOAP system can callInjectonIInjectableobjects. - Make configs ScriptableObjects:
AttackConfig: sensor radius, melee radius, melee cost, range attack cost, range attack radius, spit prefab, layer mask, attackDelay.WanderConfig: timer range, wander radius, weights, etc.BioScience(orBiosigns): hunger rates, max hunger, acceptable hunger limit, food search radius, spit restoration/depletion rates.
- Actions/sensors implement
IInjectable.Inject(DependencyInjector)to receive configs.
- Create a
-
Unity editor setup & configuration
- Create GOAP config GameObject with
GOPSetConfigFactoryandGOPRunnerBehavior; validate config. - Attach required behaviors to Llama prefab:
NavMeshAgent(set stopping distance)Animator(parameters:walk,isEating,attack)AgentBehavior,AgentMoveBehavior,LlamaBrainGOPSetBinderto bindAgentBehaviorto GOPset via GOPRunnerPlayerSensorchild (trigger collider on enemy sensors layer)
- Create ScriptableObject assets (attack config, wander config, biosigns) and reference them in
DependencyInjector. - Configure layers, collisions, and physics matrix (player layer, grass layer, enemy sensor layer).
- Animator: set parameters and transitions (
walk,isEating,attack, idle states), and add animation event for spit spawn with exact function name.
- Create GOAP config GameObject with
-
Pooling & animation events for projectile - Use Unity object pool to spawn spit prefab. - Spit prefab:
Rigidbody+ trigger collider +Spitscript (auto‑destroy after lifetime, apply force, handleOnTriggerto hit player). -SpitBehaviorlistens for animation eventBeginSpitand raises spawn event.SpitActionsubscribes and callspool.Get()to instantiate and position the spit. -
Testing and tuning - Use the GOP node viewer tool to inspect goals, current plan, and world state as seen by the GOAP system. - Tune costs, in‑range thresholds, stopping distance, and config values to achieve desired emergent behavior. - Typical tuning notes: - Wander in‑range too large causes continuous movement. - Action in‑range determines when re‑planning occurs. - Model scale affects trigger colliders and sensor radii if colliders are children and scaled.
Important implementation details, patterns & pitfalls
-
Movement
- Centralize movement logic in
AgentMoveBehavior. Actions should not implement their own movement.
- Centralize movement logic in
-
Sensors vs. events
- Prefer event‑driven triggers for player detection to avoid per‑frame physics overlap costs.
-
In‑range vs actual perform distance
- Use sensor/in‑range thresholds for planning (these can be larger than the action’s actual perform radius). Actions should still check exact distances before performing.
-
Dependency injection
- Required for non‑Mono classes (actions, sensors) to receive ScriptableObject config data. Use GOP’s config initializer/injector pattern and
IInjectable.
- Required for non‑Mono classes (actions, sensors) to receive ScriptableObject config data. Use GOP’s config initializer/injector pattern and
-
[GComponent]attribute- Auto‑populate
Animatorand other components into action data without manualGetComponentcalls.
- Auto‑populate
-
Animator events
- Use animation events to synchronize logic, e.g., spawn spit at the exact animation frame.
-
Pooling
- Use Unity pooling for projectile instantiation/reuse.
-
Scaling
- If model scale ≠ 1, child trigger collider radii may scale unexpectedly — design sensors to be scale‑invariant or account for scale.
-
Common debugging corrections shown
- Wander frequent re‑planning due to
inRange = 10→ reduce in‑range or adjust stopping distance. - Eating must wait until agent reaches grass target → set small in‑range for Eat action.
- Avoid immediate goal flips when player leaves if the agent has reason to continue its current goal (use brain logic to verify conditions).
- Make hunger/saliva publicly settable if actions modify them.
- Wander frequent re‑planning due to
Tools & resources mentioned
- Unity GOAP system by Crash Conagen (GitHub, Apache‑2.0)
- Unity APIs:
NavMeshAgent,Animator, object pooling (Unity 2021+), physics - GOP node viewer tool (debugging GOAP plans)
- ScriptableObjects for configuration
- Video sponsor / learning resource: Southern New Hampshire University (SNHU)
- Links (in video description): repo, documentation, patterns (factory, builder, Gang of Four)
Final lessons / takeaways
- GOAP gives robust, flexible decision‑making beyond simple state machines or behavior trees but requires more upfront architecture (goals, actions, sensors, world keys) and separation of concerns.
- Use config objects and dependency injection to keep actions and sensors data‑driven and easy to tune without recompiling.
- Properly tune action costs and in‑range thresholds to get the desired emergent behavior (chase vs. attack vs. eat).
- Event‑driven sensors and centralized movement/animation handling simplify performance and maintenance.
- The implementation shown is a practical template adaptable to other agents and games using the Unity GOAP package.
Speakers / sources featured
- Chris (host) — Llama / LLAcademy (presenter)
- Crash Conagen — author/maintainer of the Unity GOAP implementation
- Southern New Hampshire University (SNHU) — video sponsor
- Unity — engine & APIs (navigation, animator, pooling, physics)
- GitHub repository for Crash Conagen’s GOAP system
- Patreon / supporters named in credits: Ivan, Rulin (?), Ifis, Perry, Mustafa (and other supporters)
Category
Educational
Share this summary
Is the summary off?
If you think the summary is inaccurate, you can reprocess it with the latest model.