Траектория «Геймдев» · линия A · конспект 12 из 13

Деревья поведения (Behavior Trees)

О чём эта тема
Способ описывать сложное поведение ИИ иерархией узлов: композиты, декораторы и действия, статусы Success/Failure/Running — и инструмент Unity Behavior, реализующий эту идею графически.
Аннотация
Конспект начинается с ограничений машины состояний из A11: с ростом числа состояний количество переходов растёт быстрее, чем их можно поддерживать. Вводится дерево поведения: три категории узлов, три статуса, обход от корня на каждом такте игры и итеративное расширение логики без правки готовых ветвей. Обход дерева закрепляется интерактивным тренажёром с классической парой ветвей «бой/патруль». Затем рассматривается пакет Unity Behavior: чем граф поведения отличается от классического дерева, какие типы узлов добавляет и как данные передаются через blackboard; приводится пример собственного узла-действия на C#.
Пререквизиты
A11 — машина состояний и NavMesh; A07 — жизненный цикл, наследование; A10 — события и разделение ответственности.
Мотивация
Охранник из A11 умеет две вещи: стоять и преследовать. Добавим патрулирование, поиск аптечки, укрытие и крик о подмоге — и машина состояний начнёт задыхаться: каждое новое состояние требует переходов ко многим существующим, схема превращается в клубок. Деревья поведения решают проблему масштабирования: новая способность — это новая ветвь, а не десяток новых стрелок. Именно поэтому они стали отраслевым стандартом ИИ персонажей.

1. Устройство дерева поведения

Дерево поведения — иерархия узлов, которая при обходе сверху вниз задаёт логику поведения агента. Работа с ним итеративна: простой узел позже разворачивается в собственное поддерево с более детальной логикой. Расширение дерева вниз добавляет подробности, расширение вширь — альтернативные варианты поведения; и то и другое не требует переделывать уже готовые ветви.

Каждый узел, отработав, возвращает родителю один из трёх статусов: Success (успех), Failure (неудача) или Running (выполняется). Running — ключевой статус: он означает «я ещё не закончил, продолжим на следующем такте». Узел патрулирования возвращает Running всю дорогу до точки и лишь затем Success или Failure. Благодаря этому дерево не обязано выполняться целиком за один кадр — его работа растягивается на много игровых циклов, и сложность дерева почти не влияет на производительность. Классическое дерево при этом обходится от корня на каждом такте.

Узлы делятся на три категории:

Узлы дерева поведения
Композитные
единственные с несколькими детьми: управляют порядком выполнения и сводят статусы детей в свой
Декораторы
ровно один ребёнок: преобразуют его результат (инвертировать, повторить, проверить условие)
Листья (действия)
детей нет: содержат сами действия — суть поведения

Два главных композита. Sequence («последовательность», логическое И): выполняет детей по порядку; если ребёнок вернул Success — переходит к следующему, Failure — вся последовательность Failure, Running — Running. Selector («выбор», логическое ИЛИ): пробует детей по порядку; Failure — пробует следующего, Success или Running — возвращает его. Из этих двух кирпичей собирается типовая логика «если можешь — дерись, иначе патрулируй»:

Тренажёр · обход дерева поведения

Дерево охранника: Selector выбирает между ветвями «Бой» и «Патруль». Меняйте обстановку флажками и нажимайте «тик» — узлы подсвечиваются статусами (зелёный — Success, красный — Failure, оранжевый — Running). Заметьте: пока игрок не виден, ветвь боя проваливается на первом же условии, и Selector уходит в патруль.

selector Что делать?
sequence Бой
условие Игрок виден?
действие Подойти к игроку
действие Атаковать
sequence Патруль
действие Идти к точке маршрута
действие Ждать на точке

Нажмите «тик», чтобы выполнить один обход дерева.

Типичная ошибка Ждать, что дерево выполнится целиком за один кадр. Узлы со статусом Running растягивают работу на много тактов — «подойти к игроку» может выполняться секундами. Логика, которой нужен мгновенный ответ (например, реакция на попадание), делается событием, а не ветвью дерева.

2. Unity Behavior: граф поведения

Долгое время в Unity не было штатного инструмента для такой логики — разработчики покупали решения в Asset Store или писали свои. В конце 2024 года Unity выпустила пакет Unity Behavior — графовый редактор логики ИИ: граф прикрепляется к объекту сцены и меняет его поведение в зависимости от состояния игры.

Граф в редакторе Unity Behavior: корневой узел On Start, действие Self says, узел Random (control flow) и две ветви со стопками действий; подписаны Action node и Control Flow node
Граф в редакторе Unity Behavior: узлы действий и узел управления потоком. Источник: Unity Documentation, пакет Unity Behavior

Граф поведения умеет всё то же, что классическое дерево, но расширяет модель:

Действия в action-узлах могут «складываться» в столбик: визуально они выглядят одним блоком, но выполняются как независимые действия — нижнее не начнётся, пока статус верхнего не позволит:

Стопка из четырёх действий в одном блоке: Self says, Set Random Target, Target says, Self navigates to Target
Стопка действий: четыре независимых действия в одном визуальном блоке. Источник: Unity Documentation, пакет Unity Behavior

Так граф выглядит в работе. Слева — простой граф: условное ветвление Branch on по переменной blackboard (HasEatenPill) и повторение ветви через Repeat While — «призрак» убегает от героя, съевшего пилюлю, и преследует его в противном случае. Справа — полная версия того же поведения с зонами обнаружения и сменой цели:

Простой граф Unity Behavior: On Start, поиск героя по тегу, Branch on по переменной HasEatenPill, две ветви Repeat While — убегать или преследовать
Простой граф: ветвление по переменной blackboard. Источник: giannisakritidis.com
Полный граф поведения призрака: ветвления по расстоянию до героя, случайные точки патрулирования, повторение частей графа по условиям
Полный граф поведения «призрака» с патрулированием и погоней. Источник: giannisakritidis.com

3. Blackboard и собственный узел-действие

Дереву нужно откуда-то брать данные об обстановке: видит ли агент игрока, сколько у него здоровья. Для этого служит blackboard («классная доска») — хранилище пар «ключ — значение», общее для всего дерева. Скрипты записывают туда факты, узлы дерева читают их в условиях. Так дерево отделяется от кода игры: сенсоры пишут на доску, поведение читает с доски.

Логика конкретного действия оформляется собственным узлом — классом-наследником базового узла-действия. Пример из руководства к одной из реализаций деревьев (комментарии переведены): узел, меняющий спрайт владельца дерева.

public sealed class DisplaySprite : BT_ActionNode
{
    public Sprite sprite;                    // спрайт, который нужно показать

    private SpriteRenderer spriteRenderer;

    // вызывается один раз до первого обновления: читаем владельца с blackboard
    protected override void OnInit()
    {
        GameObject obj = blackboard.GetBlackboardValueByKey<GameObject>("Owner");
        spriteRenderer = obj.GetComponent<SpriteRenderer>();
    }

    // вызывается, когда дерево выполняет это действие
    protected override ENodeState Execute()
    {
        if (spriteRenderer != null)
        {
            spriteRenderer.sprite = sprite;
            state = ENodeState.Success;
        }
        else
        {
            state = ENodeState.Failed;
        }

        return state;
    }
}

Каркас везде одинаковый: инициализация читает нужные ссылки (часто — с blackboard), метод выполнения делает работу и возвращает статус. Точные имена базовых классов и методов зависят от инструмента — у Unity Behavior свой набор базовых типов, но устройство узла то же. А скрипт-«сенсор» с той стороны доски выглядит знакомо: обычный MonoBehaviour, который в Update записывает значение ключа (blackboard.SetBlackboardValue("ShowImage", switchSprite)).

Типичная ошибка Хранить состояние агента в полях узлов и передавать его из узла в узел напрямую. Узлы должны оставаться независимыми — обмен данными идёт только через blackboard, иначе перестановка ветвей дерева ломает логику.

Когда что выбирать. Машина состояний из A11 проще и отлично подходит для двух-четырёх состояний. Дерево поведения окупается, когда вариантов поведения много и они будут расти: для курсового проекта разумно начать с FSM и перейти на дерево, если файл с switch перестал помещаться в голове.

Контрольные вопросы

Источники

  1. Akritidis, G. How To Use Unity's Behavior Graph For AI With Behavior Trees. Part 1 // C# and Unity development : [блог]. — 2024. — URL: https://giannisakritidis.com/blog/Behavior-Graph-And-Behavior-Trees-Part1/ (дата обращения: 08.07.2026).
  2. Unity Behavior : User Manual // Unity Documentation : [сайт]. — URL: https://docs.unity3d.com/Packages/com.unity.behavior@1.0/manual/index.html (дата обращения: 08.07.2026).
  3. Behavior Tree quick tutorial : [руководство к реализации деревьев поведения]. — [Электронный ресурс, сохранённая копия в материалах курса].