Skip to content

Timers and admission nodes

Set a tree's BehaviourTreeData.timeSettings once, then select Timer for a local Float variable. Each root tree owns one BehaviourTreeTimer; subtrees share that instance. Game or AI selects the lifetime, while Scaled or Unscaled selects the Unity time source. The default is Game + Scaled.

Game time follows Unity's clock regardless of that tree's lifecycle. AI time advances only while the root is running, healthy, driven, enabled, and not paused. It freezes at pause, driver disable, end, natural completion, or fault. Reload creates a new timer and new variable instances; Restart and End/Start reuse the tree timer and preserve deadlines. Pause gates tree-driver callbacks only; it does not freeze asynchronous functions, coroutines, animation, or physics.

TimerVariable starts at zero. Reading returns remaining seconds and never starts, advances, or settles it. A positive write starts or replaces the deadline; zero or a negative write clears it. NaN and infinity throw. A timer is always local, fixed to Float, and is not a script binding.

The built-in Timer is local-scope only. Static and global variables cannot be Timers, and Timer creation is explicit rather than an extensible runtime-source factory; invalid definitions are rejected instead of being downgraded to an ordinary TreeVariable.

The root behaviour tree owns the shared timer object, and subtrees inherit it. Reads do not change timer state. AI elapsed time is settled at lifecycle transitions rather than by per-variable or per-frame timer owners.

Cooldown and Throttle take a readable duration Float and an explicit readable/writable Timer reference. They reject ordinary Float timer bindings and may intentionally share one Timer. While it is positive, admission fails without executing the child.

Node When the timer is written Child failure or interruption
Cooldown After the child succeeds Does not consume the timer
Throttle Before starting the admitted child Keeps the started timer

Countdown is a separate Service for ordinary readable/writable Float values: it subtracts elapsed root-tree time while the host branch is registered and settles once on branch exit. It uses the tree's settings and rejects Timer sources, preventing elapsed time from being counted twice.

Timeout also uses the tree's settings. Its deadline is evaluated by the existing service-check schedule: an unscaled clock may advance while timeScale is zero, but it does not make service checks execute during a stopped driver or AI Pause.

Historical names

BranchCountdown managed references use Unity's direct MovedFrom mapping to Countdown; the script meta identity is retained.

For assets containing the older Timer Service, explicitly call TimerNameMigration.Migrate(tree) in the Editor. The repair transaction rebuilds only recognized missing timer types, preserves node/variable UUIDs, canonicalizes names, and validates before saving. It does not guarantee recovery of legacy per-service timing settings.