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

Variables and types

Declare a graph variable, pick the exact type your game already uses, and decide what it starts as.

A variable is a name, a type, a shape, and a starting value. Pick the type your game already uses and the graph stops being a translation layer.

The Platformer patrol needs three things: where to walk, how it walks, and a tag for the route it is on. Flatten that into anonymous floats and you get speed, pause, face, point0_x, point0_y, and a component that spends its first line reassembling them.

EnemyPatrol.bqbehavior declares the shapes instead. route is a List of Vector2. profile is the project struct PatrolProfile, authored inline with PauseSeconds, FaceDirection, and MoveSpeed. route_tag is a string holding curious. The enemy component receives the types it declared, with no unpacking step.

  • Single for one value: a speed, a mode enum, a last known position.
  • List or Array when the graph owns several: patrol points, candidate cover spots. A list adds and removes rows; an array has an authored length.
  • Dictionary for named lookups, such as string to float tuning values. Keys are unique and authored order is kept.

Shapes nest on the GameObject path, so List<List<int>> and Dictionary<string, List<Vector3>> are both authorable. On the entity path they are not; see entity variables.

The blackboard type picker with its search field and grouped type rows
Figure 1. The whole picker. The search counts every type it can offer; the shape and the element shape are chosen above the list; a source filter sits between them and the grouped results.
Native size type picker showing the List shape, the Single element shape, and the selected Vector2 type
Figure 2. Shape and element type are separate choices. Escape closes the picker without losing the name you typed.
One declared variable row above the surfaced member bindings
Figure 3. A declared variable and a surfaced binding sit in one panel and share one namespace. The New variable… row underneath says where a declaration is saved: in this graph.
  1. Open a graph in Static and open the BLACKBOARD · WHOLE GRAPH panel in the right rail.

  2. Under Variables, choose New variable.

  3. Type the name first, in the C# identifier style the rest of the graph uses: patrol_speed, current_target, route_tag.

  4. Choose Choose a type… under the accepted name, or press Enter to move straight to type selection.

  5. Pick the shape: Single, List, Array, or Dictionary. A dictionary asks for its key type first and its value type second.

  6. Pick the exact type. Search accepts a short name or a qualified one, and two types with the same short name stay two separate identities because the graph records namespace and assembly.

  7. Edit the starting value. Numbers, bool, char, and enums use their ordinary controls; flags enums accept several members including the empty set; a project struct expands into its serialized fields; a project class is None until you create an inline instance.

Names

  • A name is unique across every other name the graph holds, which includes surfaced binding values and external service names.
  • Renaming a declaration rewrites the references to that exact declaration in the same edit.
  • Removing one leaves every old reference visible and unresolved, so the repair stays yours to make.

Types

  • A built-in scalar is saved by its C# keyword. Everything else keeps its exact type and assembly identity.
  • A project class needs [Serializable], and a project struct needs either [Serializable] or a carried unmanaged layout. Types that miss that stay listed under Not available with the reason.
  • Delegates, pointers, by-reference types, open generic definitions such as List<>, and editor-only types have no saved form. Unity.Entities.Entity is listed but unpickable, because an entity handle has no meaning until a World hands one out.
  • Collection types are declared through the Shape control instead of appearing as type rows.

Starting values

Declared type Starts as
Number, bool, char Its zero value
Enum The zero-valued member, or underlying zero when no member names it
Unity value struct Every component at zero
Project struct Every serialized field at its own default
string, project class, asset, interface, component slot None
List, array, dictionary An empty collection or None, as authored

None and empty are different states. none means there is no instance. [] means a collection exists with zero elements. [none] means a collection exists holding one null element. That distinction survives save, reopen, bake, reset, and the per-instance clone at initialization.

Object references

  • A project asset is stored by stable asset identity, so a ScriptableObject or prefab reference reopens correctly.
  • A component slot is authored as None and filled at runtime by the running GameObject graph, through a member read or write. Dropping a scene object into a saved graph value is refused instead of quietly storing a reference that cannot survive.
  • EnemyPatrolParams.bqbehavior shows the pattern: four Transform declarations, every one authored none, all populated by the running instance.

Dictionary keys use the declared key type’s equality. Strings compare ordinally and case-sensitively with no trimming, numbers by exact value, enums by underlying value, flags as a set. Empty text is a legal key and None is never one. A duplicate is refused without touching the existing entry, and when the editor cannot compute a free starter key the new entry holds <unset> until you supply one.

When it goes wrong

SymptomCheckFix
Your struct is listed under Not available.Read the reason on the row.Add [Serializable], or declare a type whose stored shape the path can carry.
A List<Vector2> will not bind to a member that takes Vector2[].Collection types need exact identity in both places.Declare the shape the member actually takes, or add an overload that takes the list.
The component slot you authored is still None in Play Mode.Nothing has written it yet.Let a member read or a member write put the concrete component into the slot, then read it from there.
A dictionary refuses Add entry.Look for an <unset> key, or a key space that has run out, such as a bool with both values used.Complete the pending key, or remove an entry before adding another.
Two variables with the same short type name behave differently.Open each row and read the qualified type.They are two identities. Pick the one your member declares.
  • Entity variables: the narrower set the unmanaged path carries.
  • Live editing: watch these values while the game runs.
  • Conversion: which variable types reach which member types, exactly.
  • Platformer: the patrol whose route, profile, and route_tag this page reads.
Full-size image