# Building game AI {#building-game-ai}


Create an entity manager and brain registry per game world rather than using
global state. Each frame, update the game-owned observations first, then call
`stepAI` with the frame delta. This keeps combat FSM updates, steering, and
brain arbitration in a predictable order.

```ts
import {
  BrainRegistry,
  ChaseEvaluator,
  createBrain,
  createCombatVehicle,
  createEntityManager,
  createVehicle,
  manage,
  setHealthPct,
  setTargetPosition,
  stepAI,
} from 'yuka-kit';

const manager = createEntityManager();
const brains = new BrainRegistry();
const player = createVehicle({ speed: 4 });
const enemy = createCombatVehicle({ speed: 3 }, { target: player });
const brain = createBrain(enemy, [new ChaseEvaluator()]);
manage(manager, enemy);
brains.register('goblin-01', brain);

// Refresh target and health observations from the game before stepping AI.
setTargetPosition(enemy, player.position);
setHealthPct(enemy, enemy.health / enemy.maxHealth);
stepAI(manager, deltaSeconds, brains);
```

Use `TacticalCombatAgent` and `BossTacticalAgent` to decide intents. The game
executes those intents; it remains responsible for damage, spawning, collision,
animation, and presentation. This separation keeps gameplay authored locally
while allowing decision behavior to be tested independently.


## Brain lifecycle {#brain-lifecycle}


Registering a different brain under an existing entity ID terminates the old
brain, including its active subgoals, before replacing it. Registering the same
brain under that ID again is a no-op. `unregister` and `reset` terminate the
brains they remove.

`BossBrain` requires at least one phase. Health thresholds must be finite
numbers between zero and one, in strictly descending order. Invalid phase
configuration throws before the owner receives any brain or phase tags.

GOAP snapshots must agree with their progress: active plans need a remaining
action, completed plans have consumed all actions, and failed plans carry no
plan progress. Already-satisfied goals may complete with an empty plan.
Invalid snapshots are rejected before an existing executor is changed.


## Intent boundary {#intent-boundary}


`TacticalCombatAgent` and `BossTacticalAgent` return command-neutral
`AgentIntent` values such as `move-to`, `move-away`, `action`, `transfer-map`,
`stop`, and `wait`. Treat that return value as a proposal, validate it in your
game's authority layer, then execute it there. The library never applies
damage, spawns an actor, changes a map, or plays an animation on its own.
