gamedev-skills/awesome-gamedev-agent-skills

ai-behavior-trees-utility-ai

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), pl…

소스 보기
원본 Skill 문서

원본 저장소의 제목, 예시, 코드, 표, 링크, 이미지를 유지해 표시합니다.

Behavior Trees & Utility AI

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.

When to use

  • Use to build a reusable BT runtime: a Blackboard, Node base, action/condition leaves,

Sequence/Selector/Parallel composites, and decorators (Inverter, Cooldown, Repeat).

  • Use to build a Utility AI decider: response curves, considerations, and an evaluator that

scores and selects actions (max, softmax, or weighted-random for variety).

  • Use to build hybrid AI — a BT whose leaf delegates the "which attack / which target"

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.

Core workflow

  1. Pick the model. Structured, prioritized, interruptible behavior → BT. Continuous

"score every option" decisions (targeting, needs, item choice) → Utility. Both → hybrid.

  1. Design the Blackboard first. One typed key/value store per agent is the shared memory that

decouples nodes; leaves read/write it and never hold references to each other.

  1. Write leaves. Conditions return Success/Failure immediately; actions return

Running across frames until they finish. Keep leaves small and side-effect-explicit.

  1. Compose. Selector = OR/fallback (first non-failure wins); Sequence = AND (stop at first

non-success); Parallel for concurrent branches. Wrap with decorators for policy (invert, cooldown, repeat, force-success).

  1. For Utility: enumerate considerations, map each raw fact through a normalized 0..1 curve,

combine (weighted product with compensation, or weighted sum), then select the max — add hysteresis so agents don't flip-flop on ties.

  1. Tick deliberately. Tick the tree/evaluator once per decision step (often slower than

render). Preserve Running state between ticks; verify by drawing the active path and the per-action scores on screen while tuning.

Architecture at a glance

A behavior tree evaluates top-down, left-to-right; each node returns a status up to its parent:

mermaid
flowchart 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:

text
facts (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:

csharp
public 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.

Utility scoring in one snippet

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.

Pitfalls

  • Re-ticking a `Running` action from the root every frame restarts it. Return Running and

resume where you left off; only Reset() a subtree when a parent actually abandons it.

  • Deep trees re-evaluated wholesale each tick waste time and cause thrash. Prefer shallow

trees and conditional aborts (a higher-priority condition can interrupt a lower branch).

  • Un-normalized considerations. If one curve outputs 0..100 and another 0..1, the big one

dominates. Every consideration must return 0..1.

  • Utility jitter on near-ties. Add hysteresis: give the currently-running action a small bonus

so the agent commits instead of oscillating.

  • Allocating nodes, closures, or arrays every tick creates GC spikes. Build the tree once at

spawn; keep per-tick work allocation-free.

References

  • references/behavior-tree-core.md — Blackboard, Node/leaf base classes, action & condition

leaves, 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 Utility

AI, 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).

Related skills

  • 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.
같은 저장소의 Skills

더 많은 Skills

모든 Skills
gamedev-skills
커뮤니티

game-feel

Add "juice" and game feel that makes actions satisfying — screen shake, hit-stop/freeze frames, tweened/eased motion, squash & stretch, knockback, and layered audio-visual feedback — as engine-neutral techniques that pair with the detected engine's tween, particle, and camera APIs. Use when the user mentions game feel, juice, "make it feel good/punchy", screen shake, hit stop, screen freeze, easing, squash and stretch, impact frames, or feedback/polish on hits, jumps, pickups, and deaths.

설치 수
4
GitHub Stars
878
업데이트
8월 24일
gamedev-skills
커뮤니티

game-ui-ux

Design and build game UI/UX — HUDs, menus, and overlays — that survive every screen: anchor- based responsive layout, resolution/aspect scaling and safe areas, keyboard/gamepad focus navigation, a screen/menu state stack, and event-driven (not polled) HUD updates. Engine- neutral patterns that pair with the detected engine's UI skill. Use when the user mentions HUD, health bar, main menu, pause menu, settings screen, UI layout, anchors, UI scaling, aspect ratio, safe area, controller/keyboard menu navigation, or wiring UI to game state.

설치 수
4
GitHub Stars
878
업데이트
8월 24일
gamedev-skills
커뮤니티

dialogue-systems

Build branching dialogue and narrative — a node/choice graph with conditions, variables, and localization hooks — and choose between authoring tools Ink and Yarn Spinner or a custom data-driven runner. Engine-neutral. Use when the user mentions dialogue system, branching dialogue, conversation tree, choices, Ink (.ink), Yarn Spinner (.yarn), or NPC dialogue.

설치 수
4
GitHub Stars
874
업데이트
8월 24일
gamedev-skills
커뮤니티

godot-2d-movement

Implement 2D kinematic character movement in Godot 4.7 with CharacterBody2D and moveandslide(): platformer run/jump with gravity, top-down 8-direction motion, slope handling, and reading collisions. Use when coding a 2D player or enemy controller, a platformer or top-down character, or fixing moveandslide()/ isonfloor() behavior in a .tscn with a CharacterBody2D.

설치 수
4
GitHub Stars
874
업데이트
8월 24일