In short, behavior trees allow specifying to a robot what it should do. It's like its brain. The old good actions and triggers serve as its hands and eyes.
Behavior trees are well-known in game development and have been used for over a decade in various projects to write AI. Therefore, there are mountains of materials on the internet; you just need to start searching.
There are more complex and flexible technologies available, but behavior trees remain one of the most common options due to their relative simplicity.
From the very early days of the program, there was a system of triggers and actions as a way to configure reactions to something - displaying an icon on the screen, collapsing/expanding windows, and so on. This approach works well but only for fairly simple conditions. Once additional elements are introduced, the configuration quickly spirals out of control, making it very difficult to understand what is happening and how to fix it. The tools I added, such as the dependency graph, only tackled the symptoms, while the core issue remained - triggers/actions are simply not suitable for modeling multi-level logic. For instance, rotating skills can be done but is quite complex.
This is where behavior trees come to the rescue - they are relatively easy to set up, flexible, and proven to be effective, as countless real robots and game bots work based on them.
First, let's remember that in EyeAuras, we have triggers and actions. Triggers react to something and can be activated or deactivated. Actions do something. This is all clear, nothing new. Now, imagine these as two completely independent things - triggers only track events (e.g., appearance of a buff/debuff, HP level dropping below normal), while actions remain the same; we just stop associating them with triggers in the old way - no more adding them to OnEnter/WhileActive/OnExit; they simply exist on their own.
All we have to do is somehow link events and actions together. And the tree allows us to do just that - specify what to do if something happens.
Trees always start from the root and consist of nodes. Each node can be (more details here):
Traversal always starts from the root, top-down, left-right. Depending on the nodes used, you can control how the final state is calculated and what decision is made.
(image source here, article in Russian)
Enough of the stuffy theory; let's take a closer look at how it actually works.
Suppose we want the character to press the "eat food" button (F1) when their HP drops below a certain value. In this example, it will be F1.
HP is low
, which somehow checks when it's time to heal. How exactly doesn't matter - it could be Color Search, ML Search, or a combination of any other triggers. It's business as usual.from the node panel, drag Aura Is Active
and link the created node to the root, then establish a connection between the trigger and the node within the node itself
from the panel, drag another node - Key Press
and specify that F1
should be pressed in this node
Overall, our tree is almost ready. Although it's not a tree yet All that's left is to indicate how often to recalculate it ("tick"). By default, the tree is recalculated every 250ms, but it can be much faster. Besides the recalculation frequency, additional conditions for the tree can be specified - if they are not met, the tree won't do anything at all. This is controlled by Is Active
in the settings of the root node. The simplest example is to link the tree to an aura with Hotkey Is Active, and then it will be activated/deactivated by pressing a button.
Now, every 250ms, the program will traverse the tree from the root top-down. If the HP is low
aura is active, then the F1
button will be pressed.
However, if the aura is NOT active, the tree recalculation will stop at this point without reaching the Key Press
action.
It's more flexible. Let me illustrate by adding a condition "press F1 no more than once every 10 seconds." All you need to do is add a Cooldown
node before Key Press
and specify how much time must pass before the character can press F1
again.
Using a similar approach, you can add any other node from the entire available arsenal. For example, here is how the tree (in two variants) looks for a character in Lineage 2
that autonomously selects targets, gathers resources, and fights mobs. By using nodes that control how the tree is traversed, very complex logic can be added.
This variant relies more on scripts for executing actions - the most flexible option but requires knowledge of C#
and scripts.