Skip to content
Bit Quirky Behavior Trees and
State Machines

Search documentation

All topics and APIs

Close returns focus to Search.

What are you looking for?

Try a common topic or enter a complete API identifier.

Browse the reference instead

Esc closes · Tab reaches results · Enter opens the focused link

v0.6.0
Menu

GameObject agents

Put a graph on a GameObject with one component, choose when it steps, and reset or replace it while the game runs.

One component turns a graph file into a running character. Add Behavior Agent to the object, point it at the graph, choose when it steps, and the object starts making decisions.

Platformer’s Enemy Platform walks a route, flips at the ends, and stops being dangerous once the player stomps it. Written by hand that is a patrol coroutine, a defeated flag, and a state enum that three other scripts read. Written as graphs it is two graph files and two components on the same object: EnemyPatrol.bqbehavior for the walking and EnemyStateMachine.bqbehavior for the mode.

Two agents on one object is the ordinary case, and it is the reason the runtime keeps one graph instance per component instead of one per GameObject.

  • Your actor already exists as a prefab with components, and you want its decisions visible without rewriting the prefab.
  • The decision has to call MonoBehaviour code, wait on a coroutine, or subscribe to a C# event. All three live on this host.
  • One object needs two independent decisions, like Platformer’s walk and its mode, each with its own progress.
  1. Open Assets/Platformer/Scenes/Platformer.unity and select Enemy Platform in the Hierarchy.

  2. Read the two Behavior Agent components already on it. The first holds EnemyPatrol, the second holds EnemyStateMachine.

  3. On your own object, choose Add Component and add Behavior Agent, then drag a .bqbehavior asset onto Graph.

  4. Set Update Mode. Update steps once per frame callback; Fixed Update steps once per fixed-step callback. Those are the two settings this release ships, and the component reads Time.deltaTime or Time.fixedDeltaTime to match.

  5. Fill in what the graph asks for. A graph that reads facts needs its binder components in Input Binder Components; a graph that emits commands needs Command Handler Components; a Move To node needs Movement Adapter Component; a graph with bindings needs Member Provider Component and any object slots under Member References.

  6. Press Play and select the object. The editor opens that agent’s graph in Live, and the card that carries RUNNING is the work the object is doing right now.

The component has no custom inspector: those fields are Unity’s own drawer over the serialized values, which is why they read as plain object and enum rows.

  • The component initializes on enable. It never parses or bakes a graph: it materializes a fresh native artifact from the cache the importer already produced, and refuses to initialize when that cache is absent.
  • An enabled component advances once from the callback its Update Mode names, and skips the other one. Nothing advances while the component is disabled.
  • One component owns one graph instance, its blackboard, its command queue, its member runtime, and its services. Two components on one object stay separate.
  • TickOnce(deltaTime, frameNumber) is public, so game code can own the schedule for a disabled agent, which is what Racing Line does for its CPU cars. An enabled agent with an update mode plus a TickOnce caller steps twice per frame, so pick one owner.
  • A step samples facts from binders and polled members, advances the core, services immediate member requests, then dispatches commands in queue order. Composed services advance once per step too: before the core for a graph with no reactive abort observers, and after command dispatch for a graph that has them. TickCount reports completed steps.
  • The composition you assign locks at initialization. Assigning a different graph, binder, handler, provider, or movement adapter afterwards is refused with a message naming the object. Update Mode is the exception and stays writable.
  • Disabling the component pauses composed services and member work and keeps the instance, its blackboard, and its runtime generation. Re-enabling resumes them. Destroying the component releases everything it owned.

Three explicit calls cover the lifecycle a game needs at runtime.

  • CancelActiveWork(frameNumber) interrupts outstanding actions, publishes cancellation commands, stops composed services, and leaves the agent terminally cancelled. Calling it twice is harmless.
  • ResetRuntime(frameNumber) cancels with the reset reason, restores authored defaults, clears execution state, and starts a new runtime generation on the same graph.
  • ReplaceGraph(nextGraph, frameNumber) releases the current graph’s state and initializes another imported graph through the same component and the same host composition.

A new generation matters to your adapters: a completion that arrives late for an old generation is stale and must be dropped instead of applied to the new activation.

When it goes wrong

SymptomCheckFix
Nothing happens, and Live never opens.Confirm Graph is assigned and the component is enabled on an active object.Assign the imported graph and enable the object. Live attaches to an initialized agent.
The wrong graph opens when you select the object.Count the Behavior Agent components on it.Select the exact component you want to watch. Attachment follows the component, not the object.
The agent steps twice per frame.Look for game code calling TickOnce on an enabled agent.Disable the component and let your code own the schedule, or drop the call and keep the update mode.
Movement requests are accepted and nothing moves.Read Movement Adapter Component on the agent.Compose the adapter that owns your character motion, as in adapters and services.
Values are back to their authored defaults after a respawn.Confirm whether your code called ResetRuntime.Reset restores authored defaults by design. Keep values that must survive in your own component.
Full-size image