Doc: Explain blackboard scopes

This commit is contained in:
Serhii Snitsaruk 2024-03-02 16:10:42 +01:00
parent bb6fab7555
commit c96e2019af
2 changed files with 67 additions and 3 deletions

View File

@ -8,7 +8,7 @@
project = 'LimboAI'
copyright = '2021-present Serhii Snitsaruk and the LimboAI contributors'
author = 'Serhii Snitsaruk'
author = 'Serhii Snitsaruk and the LimboAI contributors'
release = '1.0'
# -- General configuration ---------------------------------------------------
@ -16,6 +16,7 @@ release = '1.0'
extensions = ['sphinx_rtd_dark_mode', 'sphinx_copybutton']
master_doc = 'index'
templates_path = ['_templates']
exclude_patterns = ['_build']
@ -38,5 +39,6 @@ html_logo = "logo.png"
html_theme_options = {
'logo_only': True,
'display_version': True,
"collapse_navigation": True,
}

View File

@ -91,6 +91,68 @@ Usage example:
Advanced topic: Blackboard scopes
---------------------------------
**🛈 Note:** This section is not finished.
The :ref:`Blackboard<class_Blackboard>` in LimboAI can act as a parent scope
for another :ref:`Blackboard<class_Blackboard>`.
This means that if a specific variable is not found in the active scope,
the system will look in the parent :ref:`Blackboard<class_Blackboard>` to find it.
This creates a "blackboard scope chain," where each :ref:`Blackboard<class_Blackboard>` 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 :ref:`Blackboard<class_Blackboard>` doesn't modify values in the parent scopes.
**🛈 Note:** Blackboard scopes isolate variable namespaces and enable advanced techniques like sharing data between agents in a group.
Some scopes are created automatically. For instance, when using the :ref:`BTNewScope<class_BTNewScope>`
and :ref:`BTSubtree<class_BTSubtree>` decorators, or when a :ref:`LimboState<class_LimboState>`
has non-empty blackboard plan defined, or when a root-level :ref:`LimboHSM<class_LimboHSM>`
node is used. Such scopes prevent naming collisions between contextually separate environments.
Sharing data between several agents
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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:
.. code:: gdscript
extends BTAction
@export var group_target_var: String = "group_target"
func _tick(delta: float) -> Status:
if not blackboard.has_var(group_target_var):
var new_target: Node = acquire_target()
# Set common target shared between agents in a group:
blackboard.top().set_var(group_target_var, new_target)
# Access common target shared between agents in a group:
var target: Node = blackboard.get_var(group_target_var)
In this example, :ref:`blackboard.top()<class_Blackboard_method_top>` accesses the root scope of the
:ref:`Blackboard<class_Blackboard>` chain.
We assign that scope to each agent in a group through code:
.. code:: gdscript
class_name AgentGroup
extends Node2D
## AgentGroup node: Manages the shared Blackboard for agents in a group.
## Children of this node are assumed to be agents that belong to a common group.
## This implementation assumes that each agent has a "BTPlayer" node for AI.
@export var blackboard_plan: BlackboardPlan
var shared_scope: Blackboard
func _ready() -> void:
if blackboard_plan == null:
shared_scope = Blackboard.new()
else:
shared_scope = blackboard_plan.create_blackboard()
for child in get_children():
var bt_player: BTPlayer = child.find_child("BTPlayer")
if is_instance_valid(bt_player):
bt_player.blackboard.set_parent(shared_scope)
In conclusion, the :ref:`Blackboard<class_Blackboard>` 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.