С чего начать
Что вообще такое деревья поведения?
Если вкратце - это штука, которая позволяет указать роботу, что же ему делать. Это его мозг. Руками и глазами при этом являются старые добрые действия и триггеры. Деревья поведения очень известны в гейм-деве и уже лет больше десятка лет используются в самых разных проектах для написания ИИ, так что материалов в интернете горы, достаточно лишь начать искать. Есть как более сложные, так и более гибкие технологии, но деревья остаются одним из самых распространенных вариантов в силу своей относительной простоты.
Как они связаны с Eye Auras?
Практически с самых первых дней в программе была система триггеров и действий как способ настройки реакций на что-либо - появление иконки на экране, сворачивание/разворачивание окон и т.п. Что-то происходит (= триггер активируется) - программа на это реагирует и выполняет действие. Такой подход работает хорошо, но лишь для достаточно простых условий - как только в условие намешиваются какие-то дополнительные моменты, конфигурация очень быстро выходит из-под контроля и становится очень-очень сложно понять, что происходит и как это починить. При этом инструменты, которые я добавлял, к примеру, граф зависимостей лишь боролись с симптомами, а сама проблема оставалась на месте - триггеры/действия просто не приспособлены для моделирования многоуровневой логики, к примеру, ротацию скиллов сделать можно, но довольно сложно.
И вот здесь-то и пришли на помощь те самые деревья - они достаточно простые в настройке, гибкие и доказанно эффективные, так как на базе них трудится бесчисленное количество настоящих роботов и ботов в играх.
Как они работают?
Для начала давайте вспомним, что в EyeAuras у нас есть триггеры и действия. Одни реагируют на что-то и бывают активированы и деактивированы. Вторые делают что-то. Тут все понятно, ничего нового. А теперь представьте себе, что это две абсолютно независимых вещи - триггеры лишь отслеживают события (к примеру, появление бафа/дебафа, падение уровня HP ниже нормы и т.п.), ну а действия остаются прежними, просто мы перестаем их связывать с триггерами старым образом - никакого добавления их в OnEnter/WhileActive/OnExit, они просто живут сами по себе.
Все, что нам остается сделать это как-то связать события и действия вместе. И дерево позволяет сделать ровно это - указать что именно нужно делать, если что-то произошло.
Деревья всегде начинаются с корня и состоят из узлов, они же ноды. Каждая нода может быть (подробнее здесь):
- действием - тут все просто, нода умеет что-то делать
- условием - уже сложнее, условия могут быть самые-самые разные, задача такой ноды вернуть true/false. Очень похоже на то, что делают триггеры - проверяют условие и активируются/деактивируются
- декоратором - сами по себе эти ноды ничего не умеют, но они могут менять результаты выполнения других нод, к примеру, сделать инверсию и превратить true в false (или наоборот)
Обход всегда начинается с корня, сверху-вниз и слева-направо, при этом в зависимости от того, какие ноды использовались, вы можете контролировать, как же именно будет вычисляться финальное состояние и какое будет решение.
(изображение взято отсюда, статья на русском языке)
Давайте ближе к практике
Но хватит душной теории, давайте глянем ближе, как это вообще работает. Предположим, мы хотим, чтобы когда HP персонажа упало меньше определенного значения, он нажимал на кнопку "съесть банку". В примере это будет F1.
Входные данные:
- у нас есть пустое дерево
- у нас есть аура с именем
HP is low, которая как-то проверяет, что пришло время лечиться. Как именно нам не важно - это может быть Color Search, может быть ML Search или комбинация любых другие триггеров. Тут все по-старому.
Что нужно сделать:
-
с панели нод перетаскиваем
Aura Is Activeи связываем созданную ноду с корнем и в самой ноде создаем связь между триггером и нодой
-
с панели перетаскиваем еще одну ноду -
Key Pressи указываем в ней, что нужно нажиматьF1
-
В целом, наше дерево почти готово. Хоть это пока и не дерево :) Осталось указать насколько часто пересчитывать его ("тИкать"). По умолчанию дерево пересчитывается 1 раз в 250мс, но можно и гораздо меньше. Помимо того, насколько часто пересчитывать, можно еще указать дополнительные условия для самого дерева - если они не выполняются, то дерево вообще не будет ничего делать. За это отвечает
Is Activeв настройках корневой ноды. Самый простой пример - можно привязать дерево к ауре с Hotkey Is Active и тогда оно будет включаться/выключаться по нажатия на кнопку
Что получилось?
Теперь каждые 250мс программа будет проходить от корня дерева сверху-вниз. При этом, если аура HP is low активна, то будет нажата и кнопка F1

А вот если аура НЕ активна, то в этом месте пересчет дерева остановится, так и не дойдя до действия Key Press

А чем это лучше старого варианта?
Гибкостью. Проиллюстрирую на примере добавления условия "жать F1 не чаще, чем раз в 10 секунд". Все, что нужно сделать это добавить ноду Cooldown перед Key Press и указать, сколько времени должно пройти перед тем, как персонажу можно будет нажать F1 снова.

По аналогичной схеме можно добавлять и любую другую ноду из всего доступного арсенала, к примеру, вот так выглядит дерево(в двух вариантах) на персонажа в Lineage 2, который сам выбирает цели, собирает ресурсы и дерется с мобами. За счет использования нод, которые контролируют как обходится дерево, можно добавить очень сложной логики
А вот этот вариант больше использует скрипты для выполнения действие - наиболее гибкий вариант, но требует знания C# и скриптов
