See all glossary terms

Blackboard Pattern (Game AI)

The blackboard pattern is a common design pattern in game AI that centralizes shared data, making it accessible to all AI agents in a game. It's a shared data structure that stores and provides information about the game world, like the player's current position, health, or other relevant data.
AI agents can read from and optionally write to the blackboard, allowing them to make decisions based on the current game state.
This pattern has two main benefits:
  1. It separates AI code from direct interactions with the rest of the game world, reducing interdependencies and making the AI code more modular.
  2. It improves performance by avoiding repeated calculations. Typically, the blackboard is updated once per frame or even at a lower rate for more intensive calculations. Since the data is shared among all AI agents, they can access the same information without recalculating it.
One of the simplest ways to implement a blackboard in Godot is by defining a class with static variables to store the shared data. This approach works well well for indie game projects.
Here's an example from M4 in Learn 3D Gamedev From Zero:
class Blackboard extends RefCounted:
	signal player_died

	static var player_global_position := Vector3.ZERO
	static var is_player_dead := false: set = set_is_player_dead

	func set_is_player_dead(new_value: bool) -> void:
		is_player_dead = new_value
		if is_player_dead:
			player_died.emit()
In this example, the blackboard stores the player's position and emits a signal when the player dies. This allows mobs to detect when the player enters their cone of vision, chase the player, and stop chasing without needing a direct reference to the player node.
To use the blackboard, you first need to update its data from relevant parts of your game. For example, in the player's script, you can write:
func _physics_process(delta: float) -> void:
	# ...
	Blackboard.player_global_position = global_position

	if health <= 0:
		set_physics_process(false)
		Blackboard.is_player_dead = true
AI agents can then access this data without directly referencing the player object:
var attack_range := 100.0

func _physics_process(delta: float) -> void:
	if Blackboard.is_player_dead:
		set_physics_process(false)
		return

	var distance_to_player := global_position.distance_to(Blackboard.player_global_position)
	if distance_to_player < attack_range:
		attack()
One drawback of using static variables and a named class in Godot is that it makes the data accessible to the entire codebase, similar to singletons. If you want to avoid this, consider using a resource instead.
The blackboard pattern is particularly useful in games with many mobs or Non-Playable Characters (NPCs) that need to track the player and other game events. It's especially helpful if you know you'll be developing the game for a long time, as it provides a centralized location for storing and accessing shared data.
While this page gives a basic example adapted to indie games, it's worth noting that the pattern is widely used and scales well to complex systems, even in AAA game development.