Blackboard
Introduction
The Blackboard is another very useful tool contained in the Bot SDK.
It is a set of Keys/Values that you can use to have your own customized data.
It is like a read/write memory for Actions and Decisions that you can have per agent.
The Blackboard is also designer friendly as it is totally defined using Data Assets.
So you can have your blackboards stored and organized on your Unity project.
PS.: it is important to notice that the Blackboard data assets are just the memory layout definition.
If you have many Bots/Entities which should have the same memory layout, then all of those can point to the same Blackboard asset.
Each of those bots will then have its own memory based on the layout.
A very simple example
So, lets say that you have a character which collects some items on the map.
On your Actions and Decisions, you might want to read the amount of items that the character already collected in order to make a specific decision.
Also, if the character collects a new item, the items count should increase.
For this, you can have an entry on your blackboard, named ItemsAmount of type Integer and manage it on your actions and decisions code.
As the blackboard is used per-entity, other entities can also read the data contained on another entity's blackboard.
Creating a Blackboard Asset
On Unity, you can create a new Blackboard asset from the right click menu on the Project
tab, under Create->Quantum->Assets->AIBlackboard
.
This is the initial asset state:

Now you just need to create your own entries and set their types and names.

The types currently supported by the Blackboard are:
- Boolean;
- Byte;
- Integer;
- FP;
- Vector2;
- Vector3;
- Entity Ref.
Using the Blackboard
On your quantum_code
solution, you can already use the blackboard as a component on your entities.
C#
entity Hero[8] {
use Transform2D;
use DynamicBody;
use Prefab;
use AIBlackboardComponent;
...
}
Important!
Before actually using the Blackboard into your project, there is a mandatory setup to be performed on code.
There is a method which returns the blackboard from a given entity so the whole blackboard setup works.
But, of course, each game will have its own entities which use the Blackboard, and this will differ from game to game.
So you need to implement this method on your game.
It is a very simple task: on the quantum_code
solution, open the file named Entity.Blackboard.cs
and, on the unique method declared there, uncomment the sample code and replace all the "YourEntityType" by your own entity types which has the AIBlackboardComponent.
It will end up as something like this:
C#
public unsafe partial struct Entity {
public static AIBlackboardComponent* GetBlackboardComponent(Entity* entity) {
switch (entity->_ref._type)
{
case EntityTypes.Hero:
return &((Hero*)entity)->AIBlackboardComponent;
}
return null;
}
}
Referencing a Blackboard asset
The AIBlackboardComponent
contains a field named Board
, which points to the blackboard data asset that you created on Unity.
You can make the reference by using the DB or by using Asset Links.
C#
hero->AIBlackboardComponent.Board = playerData.BlackboardLink;
// Or
hero->AIBlackboardComponent.Board = DB.FindAllAssets<AIBlackboard>()[0];
This is enough to already read/write data from the entity's personal blackboard.
But there is another handy asset to be highlighted before diving into read/write snippets.
Initializing Blackboard Component Memory
Because the types and amount of different data stored on a blackboard is not created in a static context (by code generation for example) the memory for each component needs to be stored on the frame in a custom manner as UserData (opposed to being saved on the game state like all other entities/components).
Each Blackboard component needs to reserve it's memory by calling Frame.CreateBlackboardMemory()
once after the entity has been created. It's essential to release the memory before the entity is destoyed some time later by calling Frame.DestroyBlackboardMemory()
. When "Failed to allocate memory" messages are shown you most likely forgot to release the blackboard memory.
C#
var hero = f.CreateHero();
// Call CreateBlackboardMemory before further configuration of the blackboard component.
f.CreateBlackboardMemory(&hero->AIBlackboardComponent);
// Continue the initialization.
var data = f.GetPlayerData(player);
if (data.BlackboardInitializer.Instance != null) {
AIBlackboardInitializer.InitializeBlackboard(f, &hero->AIBlackboardComponent, data.BlackboardInitializer.Instance, null );
}
// Call DestroyBlackboardMemory before destroying the hero
f.DestroyBlackboardMemory(&hero->AIBlackboardComponent);
f.DestroyHero(hero);
The Blackboard Initializer asset
This asset aims to help with a blackboard's initialization.
It mirrors a blackboard's entries and, for each entry, you can define a default value to be applied on the blackboard during initialization.
To create a Blackboard Initializer asset, right click on the Project tab and choose Create->Quantum->Assets->AIBlackboardInitializer
.
This will be its initial state:

Then, you have to choose what will be the blackboard asset to be initialized by this asset.
When you that, the blackboard's entries will already show up on the initializer asset.
You can then click on the Add Field
button if you want to define some initial value for that entry.
It will look like this:

Now, on your simulation code, you can choose to initialize your AIBlackboardComponent
from your initializer asset.
This is the code snippet needed for this:
C#
AIBlackboardInitializer.InitializeBlackboard(f, &guy->AIBlackboardComponent, data.BlackboardInitializer.Instance, null);
Note that data.BlackboardInitializer
is just an asset link to some BlackboardInitializer asset.
You can also load it using DB.FindAsset<AIBlackboardInitializer>("Guid");
PS.: if you want, you can take a look at Bot SDK Sample which has a sample code to initialize a Blackboard component based on the Blackboard Initializer Asset.
Re-initializing Blackboards upon entity respawn
If you destroy some entity and then create that same entity again, like during some respawn, that entity's blackboard will already contain the values related to its previous life cycle.
So, it is advised that you re-initialize your Blackboard data for any spawned entity to prevent old data from being used.
The BlackboardInitializer
asset is very useful in this situation.
Just execute AIBlackboardInitializer.InitializeBlackboard()
for every spawned entity.
Reading and Writing to the Blackboard
To read/write data to an entity blackboard:
C#
var bb = Entity.GetBlackboardComponent(e);
// To read
var value = bb->Board.GetValue("someKey");
// To write
bb->Board.Set("someKey", value, frame, bb);
PS.: Bot SDK from version 1.0 RC2 and on already comes with some sample Actions/Decisions which reads/writes to the Blackboard.
On your quantum_code
solution, you can go to the folder BotSDK/Samples
and check the files IncreaseBlackboardInt.cs
, SetBlackboardInt.cs
and HFSM.CheckBlackboardInt.cs
The Blackboard on the Visual Editor
The Visual Editor already comes with a sub-menu for the Blackboard.
It is named Blackboard Variables and it is accessible on the left side panel:

Press the + button in order to create new blackboard variables.
When creating/editing a new entry, you need to define:
- The variable's
Name
, which is internally used as a Key on the blackboard asset to retrieve some variable's value; - The variable's
Type
, which you can select from the dropdown menu; - The
HasDefault
checkbox, used to inform if this variable will or not be initialized to a default value upon setup; - The
Default
value to be used.

You can have many entries, with many types and not all of them needs to have a default value:

Now, whenever you compile your project, two extra data assets will automatically be created on the folder Assets/Resources/DB/CircuitExport/Blackboard_Assets
:
- A Blackboard asset which entries are the ones defined by the compiled HFSM;
- and a Blackboard Initializer asset which entries and default values are also the ones defined by the compiled HFSM.

Blackboard Nodes
With the variables in hand, you can drag and drop them to the graph in order to create Blackboard Nodes. These nodes always have two outbound slots: the Key
and the Value
.

The Key
slot is used to be linked to fields of type AIBlackboardValueKey
, which can be used to replace hardcoded strings when informing the key of the variable to get/set. And, of course, by removing the hardcoded keys, the code gets more flexible on reliable. Let's analyze the get and set Before/After:
C#
var bb = Entity.GetBlackboardComponent(e);
// -- BEFORE --
// To read
var value = bb->Board.GetValue("someKey");
// To write
bb->Board.Set("someKey", value, frame, bb);
// -- AFTER --
public AIBlackboardValueKey PickupsKey;
// To read
var value = bb->Board.GetValue(PickupsKey.Key);
// To write
bb->Board.Set(PickupsKey.Key, value, frame, bb);
With that new field declared, you can go to the Visual Editor and link it to any Blackboard Node's Key
slot to it. For example:
Besides of using the Key
slot like this, it is also possible to link the Value
slot to define fields of that same type. The Default
value defined on the left panel is the value which will be baked into the asset.
When to use the Blackboard and its Nodes
Use it whenever you want to store some data per-entity which can change during runtime. If you need to define values which will never change, consider using the Constants panel instead.
Blackboard's Frame Methods
The Blackboard implements these Frame's partial methods: InitUser
, FreeUser
, AllocUser
and CopyFromUser
.
If your game already contains an implementation for those methods, a conflict will be generated.
To avoid this, you can set the compiler symbol USE_BLACKBOARD_FRAME_METHODS
.
This will prevent the Blackboard from implementing the partial methods.
For each of those methods, you will have a substitute method.
They are: InitBlackboard
, FreeBlackboard
, AllocBlackboard
, CopyFromUserBlackboard
, SerializeBlackboard
and DeserializeBlackboard
.
You just need to make sure that all those methods will still be called by the Frame's equivalent methods.
Back to top