<88> Inspecting task properties and blackboard
<89> When you click on a task in the LimboAI debugger, its properties are shown in the remote Inspector panel, including the <l1>Blackboard</l> reference. Click the <l2>Blackboard</l> to open it and view all variables across the full scope chain, grouped by scope. You can also edit variable values live, which can be useful for testing and debugging your game’s AI.
<90> Creating custom tasks
<91> By default, user tasks should be placed in the <1/> directory. You can set an alternative location for user tasks in the <2/> (To see those options, <3/> should be enabled in the Project Settings).
<92> Each subdirectory within the user tasks directory is treated as a category. Therefore, if you create a subdirectory named “motion_and_physics,” your custom tasks in that directory will automatically be categorized under “Motion And Physics.”
<93> When creating custom tasks, <b>extend one of the following</b> base classes: <l1>BTAction</l>, <l2>BTCondition</l>, <l3>BTDecorator</l>, <l4>BTComposite</l>. More on task types you can read in the <l5>Introduction to Behavior Trees</l>.
<94> <b>🛈 Note:</b> To help you write new tasks, you can add a script template to your project using “Misc → Create script template” menu option.
<95> Using the <l1>Blackboard</l> is covered in <l2>Accessing the Blackboard in a Task</l>.
<96> Task anatomy
<97> Example 1: A simple action
<98> Example 2: InRange condition
<99> Creating tasks in C#
<100> You can use the following script template for custom tasks:
<101> Sharing data using Blackboard
<102> To share data between different tasks and states, we employ a feature known as the <l1>Blackboard</l>. The <l2>Blackboard</l> serves as a central repository where tasks and states can store and retrieve named variables, allowing for seamless data interchange. Each instance of a behavior tree or a state machine gets its own dedicated <l3>Blackboard</l>. It has the capability to store various data types, including objects and resources.
<103> Using the <l1>Blackboard</l>, you can easily share data in your behavior trees, making the tasks in the behavior tree more flexible.
<104> Accessing the Blackboard in a Task
<105> Every <l1>BTTask</l> has access to the <l2>Blackboard</l>, providing a straightforward mechanism for data exchange. Here’s an example of how you can interact with the <l3>Blackboard</l> in GDScript:
<106> If you are accessing a variable that holds an object instance, and it is expected that the instance may be null or freed, you can do it like this:
<107> It is recommended to suffix variable name properties with <1/>, like in the example above, which enables the inspector to provide a more convenient property editor for the variable. This editor allows you to select or add the variable to the blackboard plan, and provides a warning icon if the variable does not exist in the blackboard plan.
<108> <b>🛈 Note:</b> The variable doesn’t need to exist when you set it in code.
<109> Editing the Blackboard Plan
<110> The Blackboard Plan, associated with each <l1>BehaviorTree</l> resource, dictates how the <l2>Blackboard</l> initializes for each new instance of the <l3>BehaviorTree</l>. BlackboardPlan resource stores default values, type information, and data bindings necessary for <l4>BehaviorTree</l> initialization.
<111> To add, modify, or remove variables from the Blackboard Plan, follow these steps:
<112> Open the LimboAI editor and load the behavior tree you want to edit.
<113> In the editor, click on the small button located inside the tab. This will open the <l1>BlackboardPlan</l> in the Inspector.
<114> In the Inspector, click the “Manage…” button to show the blackboard plan editor.
<115> In the blackboard plan editor, you can add, remove, or reorder variables, and modify their data type and hint.
<116> The hint provides additional information about the variable to the Inspector, such as minimum and maximum values for an integer variable. Learn more about <l1>property hints in the official Godot documentation</l>.
<117> You can specify the default values of the variables directly in the Inspector.
<118> Overriding variables in BTPlayer
<119> Each <l1>BTPlayer</l> node also has a “Blackboard Plan” property, providing the ability to override values of the BehaviorTree’s blackboard variables. These overrides are specific to the BTPlayer’s scene and do not impact other scenes using the same <l2>BehaviorTree</l>. To modify these values:
<120> Select the BTPlayer node in the scene tree.
<121> In the Inspector, locate the “Blackboard Plan” property.
<122> Override the desired values to tailor the blackboard variables for the specific scene.
<123> Task parameters
<124> In some cases, it can be beneficial to allow behavior tree tasks to export parameters that can either be <b>bound to a blackboard variable or specified directly</b> by the user. For this purpose, LimboAI provides special parameter types that begin with “BB”, such as <l1>BBInt</l>, <l2>BBBool</l>, <l3>BBString</l>, <l4>BBFloat</l>, <l5>BBNode</l>, and more. For a complete list, please refer to the <l6>BBParam</l> class reference.
<125> Usage example:
<126> Connecting variables in BTs to HSMs: Variable mapping
<127> Each <l1>BTState</l> creates a new blackboard scope for its BehaviorTree instance. Because BehaviorTrees are reusable resources that can run in different contexts or on different agents, they do not automatically see variables defined in the HSM. At runtime, HSM variables are usually accessible inside the BT via the parent scope blackboard, but the recommended way to access them is through <b>mapping</b>.
<128> Note
<129> To learn more about scopes, see <l1>Blackboard</l>.
<130> When both the BehaviorTree and the HSM declare variables in their respective <l1>BlackboardPlan</l> resources, the editor provides a <b>Mapping</b> section in the BlackboardPlan inspector. Mapping is the intended and recommended way to connect variables between related plans.
<131> Key points about mapping
<132> Mapping connects two variables so they behave as a single logical variable at runtime.
<133> Linked variables are updated immediately in both scopes — they literally share the same state in memory (no polling or copying).
<134> Mapping is explicit: you decide which variables the BT exposes as inputs and outputs.
<135> Linkage is bidirectional — there is no distinction between input and output.
<136> Mapping does not create new variables automatically — the variables must already exist in both blackboard plans before they can be linked.
<137> Inspector workflow
<138> Define the required variables in each BlackboardPlan (HSM plan and BT plan, for example).
<139> Select the <l1>BTState</l> node in the scene or a <l2>BTSubtree</l> inside a behavior tree.
<140> In the Inspector, select the Blackboard Plan property.
<141> In the BlackboardPlan resource inspector, locate the <b>Mapping</b> section.
<142> Create mappings by pairing variables (<1/>).
<143> On startup the mappings are applied, and the variables are automatically linked for the running instance.
<144> Programmatic alternative: linking variables in code
<145> You can also link variables directly in code using <l1>Blackboard.link_var</l>:
<146> Best practices
<147> Declare all BT dependencies in the BT’s BlackboardPlan instead of relying on parent scopes.
<148> Use <b>Mapping</b> to explicitly declare which variables should be shared with the HSM.
<149> Prefer the inspector-based Mapping workflow for clarity and editor support; use <1/> only when runtime or programmatic setup is required.
<150> Avoid writing to <1/> from inside BT tasks unless you have a very specific reason and accept the coupling it introduces.
<151> Advanced topic: Blackboard scopes
<152> The <l1>Blackboard</l> in LimboAI can act as a parent scope for another <l2>Blackboard</l>. This means that if a specific variable is not found in the active scope, the system will look in the parent <l3>Blackboard</l> to find it. This creates a “blackboard scope chain,” where each <l4>Blackboard</l> can have its own parent scope, and there is no limit to how many blackboards can be in this chain. It’s important to note that the <l5>Blackboard</l> doesn’t modify values in the parent scopes.
<153> Scopes are created automatically to prevent naming collisions between contextually separate environments:
<154> Within <l1>BTNewScope</l>.
<155> Under <l1>BTSubtree</l> decorators.
<156> With <l1>LimboState</l> that have a non-empty blackboard plan defined.
<157> Under <l1>LimboHSM</l> nodes: A new scope is created at the root level, and each <l2>BTState</l> child also receives its own separate scope.
<158> Sharing data between several agents
<159> The blackboard scope mechanism can also be used for sharing data between several agents. In the following example, we have a group of agents, and we want to share a common target between them:
<160> In this example, <l1>blackboard.top()</l> accesses the root scope of the <l2>Blackboard</l> chain. We assign that scope to each agent in a group through code:
<161> In conclusion, the <l1>Blackboard</l> scope chain not only prevents naming conflicts that can occur between state machines, behavior trees, and sub-trees, but it can also be used to share data between several agents.
<162> Debugging blackboard variables
<163> When debugging a running project, you can inspect <l1>Blackboard</l> variables in the remote Inspector. Click on a task in the LimboAI debugger to view its properties, then click the <l2>Blackboard</l> reference to see all variables across the full scope chain, grouped by scope. Variables can be edited live to aid in debugging. For state machines, select a <l3>LimboState</l> node in the Remote Scene Tree to access its <l4>Blackboard</l> in the same way.
<164> Accessing nodes in the scene tree
<165> There are several ways to access nodes in the agent’s scene tree from a <l1>BTTask</l>.
<166> <b>🛈 Note:</b> The root node of the agent’s scene tree can be accessed with the <l1>scene_root</l> property.
<167> With <1/> property
<168> With <1/> property
<169> Using blackboard plan
<170> You can <l1>create a blackboard variable</l> in the editor with the type <2/> and point it to the proper node in the <l3>BTPlayer</l> blackboard plan. By default, any <4/> variable will be replaced with the node instance when the blackboard is instantiated at runtime (see <l5>BlackboardPlan.prefetch_nodepath_vars</l>).
<171> The property BTPlayer.prefetch_nodepath_vars should be set to <1/>.
<172> Create State Machines
<173> This guide will show how to set up and use a state machine using <l1>LimboHSM</l>.
<174> Initialization
<175> To use the <l1>LimboHSM</l> state machine, you first need to initialize it in your code. This is typically done in the <2/> function of your script. Here’s an example of how to do this:
<176> In this example, we first declare the state machine and the states we want to use. Then, in the <1/> function, we add transitions between the states. Finally, we initialize the state machine and set it to active.
<177> State example
<178> You can define the behavior of a state in a script and attach it to the state node. Here’s an example of a state that plays an animation on an <1/> and waits for it to finish:
<179> In this example, the <1/> method is called when the state is entered, and it plays the specified animation. The <2/> method is called every frame, and it checks if the animation is finished. If it is, it dispatches the <3/> event, which can result in a transition to the next state.