Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build a production behavior-tree runtime (Blackboard, action/condition leaves, sequence/selector/parallel composites, decorators) and a Utility AI system (response curves — linear, exponential, sigmoid, quadratic — considerations, and action evaluators), plus hybrid BT-drives-Utility agents. Use when implementing a reusable behavior-tree or utility-based decision system, or tuning enemy/NPC decisions beyond a simple FSM, or when the user mentions behavior tree, blackboard, decorator, selector, s
.claude/skills/gamedev-skills-ai-behavior-trees-utility-ai/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✓→✗ | ▼ Worse | 52% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 29% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 78% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 57% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 80% | 0% |
Two complementary ways to structure NPC decision-making, plus how to combine them. A behavior tree (BT) expresses structured, prioritized, reactive logic as a tree that is "ticked" each step. Utility AI answers "how much do I want each option right now?" by scoring actions with normalized curves and picking the best. Ship believable agents by using a BT for structure and Utility AI where graded trade-offs matter.
This skill is the implementation companion to game-ai (which helps you choose between FSM / BT / steering / pathfinding). Read game-ai to pick a model; read this to build the runtime.
Blackboard, Node base, action/condition leaves,Sequence/Selector/Parallel composites, and decorators (Inverter, Cooldown, Repeat).
scores and selects actions (max, softmax, or weighted-random for variety).
choice to a utility evaluator.
When not to use: to choose between FSM, BT, steering, or pathfinding, and for A/navmesh routing, use `game-ai`. For Unreal's asset-based `BehaviorTree`/`Blackboard`, `BTTask`/`BTService` and `AIController`, use `unreal-behavior-trees`. For the navmesh agent that moves the NPC, use unity-navmesh or the engine's navigation node.
"score every option" decisions (targeting, needs, item choice) → Utility. Both → hybrid.
decouples nodes; leaves read/write it and never hold references to each other.
Success/Failure immediately; actions returnRunning across frames until they finish. Keep leaves small and side-effect-explicit.
Selector = OR/fallback (first non-failure wins); Sequence = AND (stop at firstnon-success); Parallel for concurrent branches. Wrap with decorators for policy (invert, cooldown, repeat, force-success).
combine (weighted product with compensation, or weighted sum), then select the max — add hysteresis so agents don't flip-flop on ties.
render). Preserve Running state between ticks; verify by drawing the active path and the per-action scores on screen while tuning.
A behavior tree evaluates top-down, left-to-right; each node returns a status up to its parent:
mermaidflowchart TD Root["Selector (root)"] --> Combat["Sequence: Combat"] Root --> Patrol["Action: Patrol"] Combat --> See["Condition: CanSeePlayer?"] Combat --> InRange{"Selector: Reach"} Combat --> Attack["Action: Attack (Running)"] InRange --> Close["Condition: InAttackRange?"] InRange --> MoveTo["Action: MoveToPlayer (Running)"]
Utility AI is a scoring pipeline — every candidate action is scored, then one is selected:
textfacts (distance, health, ammo…) │ each fact → a normalized 0..1 response curve (consideration) ▼ score(action) = weight · combine(consideration_1 … consideration_n) # product+compensation or sum ▼ select: argmax · or softmax / weighted-random for variety · + hysteresis to avoid jitter
Status is a three-value enum shared by every node — this is the contract that makes the tree composable:
csharppublic enum Status { Success, Failure, Running } public abstract class Node { public abstract Status Tick(Blackboard bb, float dt); public virtual void Reset() { } // called when a parent abandons this subtree }
csharp// Selector = fallback/OR: return the first child that is not Failure. public sealed class Selector : Composite { public override Status Tick(Blackboard bb, float dt) { for (; _current < Children.Count; _current++) { var s = Children[_current].Tick(bb, dt); if (s != Status.Failure) return s; // Success or Running stops the scan } _current = 0; return Status.Failure; // every child failed } }
The reciprocal Sequence (AND — stop at first non-Success), Parallel, the Blackboard, the leaf base classes, and every decorator are in references/behavior-tree-core.md.
csharp// A consideration maps one raw fact to 0..1 through a response curve. float Score(Blackboard bb) { float distance01 = Curves.InverseLerp01(bb.Get<float>("distToPlayer"), 20f, 2f); // near = 1 float health01 = Curves.Sigmoid(bb.Get<float>("health01"), k: 8f, mid: 0.4f); // hurt = low // Product + compensation keeps a single 0 from vetoing while low values still dampen. return Curves.CompensatedProduct(new[] { distance01, health01 }); }
The full curve library (linear, quadratic, exponential, logistic/sigmoid, smoothstep), the Consideration/UtilityAction types, and the UtilityEvaluator selection strategies are in references/utility-ai-system.md.
Running action from the root every frame restarts it. Return Running andresume where you left off; only Reset() a subtree when a parent actually abandons it.
trees and conditional aborts (a higher-priority condition can interrupt a lower branch).
dominates. Every consideration must return 0..1.
so the agent commits instead of oscillating.
spawn; keep per-tick work allocation-free.
references/behavior-tree-core.md — Blackboard, Node/leaf base classes, action & conditionleaves, Sequence/Selector/Parallel, and the decorator library (full C#).
references/utility-ai-system.md — response-curve library, Consideration, UtilityAction,and the UtilityEvaluator (argmax, softmax, weighted-random, hysteresis).
references/practical-examples.md — a guard Patrol→Combat BT, a villager needs-based UtilityAI, and a hybrid agent, as drop-in templates.
references/best-practices-and-pitfalls.md — memory management, profiling, avoiding deep trees,event-driven aborts, and combining Utility AI with BTs (hybrid architecture).
game-ai — choose between FSM / BT / steering; A and navmesh pathfinding.unreal-behavior-trees — Unreal's asset-based BT/Blackboard, tasks, decorators, services.unity-navmesh — the NavMeshAgent that carries out "move to" intents.physics-tuning — agent radius, movement, and collision response for the motion layer.tower-defense, fps-shooter, rpg — genres that compose this decision layer.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 25,860 | 19,391 | -25% | 1 | 1 | 0% | 4,981 | 6,411 | +29% | 0 | 0 | — |
case-02 | fail→fail | 42,085 | 34,551 | -18% | 1 | 1 | 0% | 8,277 | 8,749 | +6% | 0 | 0 | — |
case-03 | pass→fail | 26,143 | 21,887 | -16% | 1 | 1 | 0% | 3,732 | 5,667 | +52% | 0 | 0 | — |
case-04 | pass→pass | 20,208 | 24,654 | +22% | 1 | 1 | 0% | 3,748 | 6,666 | +78% | 0 | 0 | — |
case-05 | pass→pass | 17,253 | 17,265 | +0% | 1 | 1 | 0% | 3,246 | 5,112 | +57% | 0 | 0 | — |
case-06 | pass→pass | 16,751 | 17,816 | +6% | 1 | 1 | 0% | 2,814 | 5,070 | +80% | 0 | 0 | — |
case-07 | pass→pass | 15,117 | 13,416 | -11% | 1 | 1 | 0% | 2,349 | 4,274 | +82% | 0 | 0 | — |
case-08 | pass→pass | 22,306 | 14,738 | -34% | 1 | 1 | 0% | 2,767 | 4,825 | +74% | 0 | 0 | — |
case-09 | pass→pass | 16,028 | 13,361 | -17% | 1 | 1 | 0% | 2,566 | 4,409 | +72% | 0 | 0 | — |
case-10 | pass→pass | 16,755 | 15,449 | -8% | 1 | 1 | 0% | 2,734 | 4,298 | +57% | 0 | 0 | — |
case-11 | pass→pass | 20,889 | 21,643 | +4% | 1 | 1 | 0% | 3,288 | 5,574 | +70% | 0 | 0 | — |
case-12 | pass→pass | 22,504 | 27,985 | +24% | 1 | 1 | 0% | 2,341 | 4,926 | +110% | 0 | 0 | — |
case-13 | pass→pass | 17,100 | 19,488 | +14% | 1 | 1 | 0% | 2,967 | 4,836 | +63% | 0 | 0 | — |
case-14 | pass→pass | 16,965 | 17,660 | +4% | 1 | 1 | 0% | 2,900 | 5,089 | +75% | 0 | 0 | — |
case-15 | pass→pass | 16,932 | 15,426 | -9% | 1 | 1 | 0% | 2,543 | 4,434 | +74% | 0 | 0 | — |
case-16 | pass→pass | 15,717 | 15,121 | -4% | 1 | 1 | 0% | 2,414 | 4,301 | +78% | 0 | 0 | — |
case-17 | pass→pass | 19,494 | 32,277 | +66% | 1 | 1 | 0% | 3,491 | 4,346 | +24% | 0 | 0 | — |
case-18 | fail→fail | 17,745 | 14,388 | -19% | 1 | 1 | 0% | 2,609 | 4,266 | +64% | 0 | 0 | — |
case-19 | pass→pass | 17,923 | 18,746 | +5% | 1 | 1 | 0% | 2,825 | 5,189 | +84% | 0 | 0 | — |
case-20 | pass→pass | 17,389 | 16,383 | -6% | 1 | 1 | 0% | 2,795 | 4,921 | +76% | 0 | 0 | — |
case-21 | pass→pass | 15,297 | 25,263 | +65% | 1 | 1 | 0% | 2,590 | 4,938 | +91% | 0 | 0 | — |
case-22 | pass→pass | 20,516 | 27,957 | +36% | 1 | 1 | 0% | 3,134 | 5,147 | +64% | 0 | 0 | — |
case-23 | pass→pass | 19,346 | 38,087 | +97% | 1 | 1 | 0% | 3,780 | 8,422 | +123% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of -100 percentage points is the difference between those two pass rates over the 23 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Other measured skills in the registry, with their headline benchmark lift.