High Level Overview - Terasology/Behaviors GitHub Wiki

Here you can find an overview of some of the inner workings of the Behavior system.

In Terasology, the Behavior system is composed of:

  • A Behavior component, used for associating entities with behaviors;
  • Two components associated with groups, GroupTag and GroupMind;
  • An implementation of behavior trees and their related mechanisms (used to describe the behavior of an entity or a group of entities);
  • A decorated entity called Actor, used to facilitate the process of adding behaviors to a given entity;
  • An asset mechanism for loading .behavior and .group from the assets structure (on disk); and
  • An in-game editor for behavior trees (currently unstable).

More details on each of the parts can be found below:

Components

The Behavior component is used to associate an existing behavior with an entity or creature. Behaviors are structured as behavior trees and are loaded as assets from behavior files (.behavior). This component holds two different objects:

  • A BehaviorTree, deserialized from a behavior file; and
  • An Interpreter, responsible for evaluating the behavior tree.

The GroupTag component is used to assign an entity or creature to a group. Also, the GroupMind component is used in conjunction with GroupTag in specific group-related scenarios, where all entities within a group must possess not only the same behavior tree but also the same behavior states (acting in unison). For more details on how the group mechanism works please see this link.

Behavior trees

Behavior trees are the structures used to describe the behavior of an entity within the game. A behavior is a pre-defined set of actions performed by an entity, triggered by specific conditions or events. Behaviors can be related to movement (animals wandering in an open field) or more complex actions (searching for water sources to fulfill a specific need). A graphical illustration of a typical behavior tree is shown below:

Behavior trees are composed of different nodes, which determine if the behavior will be performed sequentially, or if it will be subject to any conditions, etc. The illustration above has sequential nodes (right arrows), determining that everything below them will happen in a sequence (from left to right), and condition nodes (question marks), determining that everything below them will happen (in sequence) only if a determined condition is satisfied. In Terasology, nodes are objects implementing the TreeNode interface. There are composite nodes, action nodes, and decorators, but in an effort not to duplicate information too much, here's a link to the part of the wiki that explains the TreeNode interface in detail.

Every Actor instance (see description below) has an associated Interpreter. That interpreter uses a BehaviorTreeRunner (currently DefaultBehaviorTreeRunner as we aren't using the bytecode/ASM parts of the system) to work on the given tree - there is a BehaviorTreeRunner for every given Actor. What's important is the BehaviorTree is a data class; it provides the underlying tree data, but it's shared between Actors, using the Interpreter/BehaviorTreeRunner combo.

Both BehaviorTree and Interpreter can also be instantiated and assigned to an entity during gameplay (for example, when entities join a group and must adopt a different behavior). In this case, the BehaviorTree instance is replaced by a new one, while the Interpreter can be created as a new instance or it can be replaced by another existing instance (this is particularly important in cases where an entity must not only assume the new behavior but also have its state placed in a specific point within the behavior tree).

Actor

The Actor is a decorated Entity, a class that facilitates adds Behavior related functionality to a given Entity. It represents an entity with a behavior.

Important parts of the Actor class:

  • Actor(EntityRef) constructor - an Actor can only be constructed over a given Entity.
  • getEntity() - returns the underlying entity.
  • getComponent(), getComponentField(), hasComponent() - QoL methods providing easier access to some parts of the underlying entity.
  • save(Component component) - assigns a component to the current Actor. This method is used when new components are assigned to the Actor, or in some cases when existing components are modified.

Other important parts of the Actor class are:

  • DataMap functionality (Map<Integer, Object> dataMap): used by every Behavior Node to manipulate its stateful information, so the Nodes themselves can be stateless/reusable. The id arguments used in its related getValue() and setValue() methods are the tree-unique IDs of the Nodes.

  • Map<String, Object> blackboard: used to facilitate inter-node communication. While in dataMap every node has its own little corner where it stores its info, blackboard is the shared space where nodes can co-ordinate any higher level stateful goals.

Assets

Behaviors are JSON-like files that describe a behavior tree, containing pre-defined elements (nodes) and actions associated with these nodes. These files (.behavior) are located in the assets/behaviors folder of each module.

Each entity can have a behavior component included in its .prefab file as:

"Behavior" : {
    "tree" : "<module>:<behavior>"
}

Where <behavior> refers to the name of the behavior, and <module> refers to the module in which the behavior is defined. You can use any pre-made behavior existing in another module. If you use the stray behavior from the Behaviors module, for example, your .prefab behavior entry will be:

"Behavior" : {
    "tree" : "Behaviors:stray"
}

If you create your own .behavior file, you don't need to reference the module in the .prefab file - e.g. if you created a custom run.behavior file, your prefab should look like this:

"Behavior" : {
    "tree" : "run"
}

A curated list of pre-made behaviors can be found here.

GUI Editor

Behavior trees can also be created or edited through the use of the Behavior GUI editor. The GUI editor is currently unstable, but its latest version can be accessed in-game through the F5 key. At this moment, we recommend that you edit your .behavior files directly.

⚠️ **GitHub.com Fallback** ⚠️