Если вкратце - это штука, которая позволяет указать роботу, что же ему делать. Это его мозг. Руками и глазами при этом являются старые добрые действия и триггеры.
Деревья поведения очень известны в гейм-деве и уже лет больше десятка лет используются в самых разных проектах для написания ИИ, так что материалов в интернете горы, достаточно лишь начать искать.
Есть как более сложные, так и более гибкие технологии, но деревья остаются одним из самых распространенных вариантов в силу своей относительной простоты.
Практически с самых первых дней в программе была система триггеров и действий как способ настройки реакций на что-либо - появление иконки на экране, сворачивание/разворачивание окон и т.п. Что-то происходит (= триггер активируется) - программа на это реагирует и выполняет действие. Такой подход работает хорошо, но лишь для достаточно простых условий - как только в условие намешиваются какие-то дополнительные моменты, конфигурация очень быстро выходит из-под контроля и становится очень-очень сложно понять, что происходит и как это починить. При этом инструменты, которые я добавлял, к примеру, граф зависимостей лишь боролись с симптомами, а сама проблема оставалась на месте - триггеры/действия просто не приспособлены для моделирования многоуровневой логики, к примеру, ротацию скиллов сделать можно, но довольно сложно.
И вот здесь-то и пришли на помощь те самые деревья - они достаточно простые в настройке, гибкие и доказанно эффективные, так как на базе них трудится бесчисленное количество настоящих роботов и ботов в играх.
Для начала давайте вспомним, что в EyeAuras у нас есть триггеры и действия. Одни реагируют на что-то и бывают активированы и деактивированы. Вторые делают что-то. Тут все понятно, ничего нового. А теперь представьте себе, что это две абсолютно независимых вещи - триггеры лишь отслеживают события (к примеру, появление бафа/дебафа, падение уровня HP ниже нормы и т.п.), ну а действия остаются прежними, просто мы перестаем их связывать с триггерами старым образом - никакого добавления их в OnEnter/WhileActive/OnExit, они просто живут сами по себе.
Все, что нам остается сделать это как-то связать события и действия вместе. И дерево позволяет сделать ровно это - указать что именно нужно делать, если что-то произошло.
Деревья всегде начинаются с корня и состоят из узлов, они же ноды. Каждая нода может быть (подробнее здесь):
Обход всегда начинается с корня, сверху-вниз и слева-направо, при этом в зависимости от того, какие ноды использовались, вы можете контролировать, как же именно будет вычисляться финальное состояние и какое будет решение.
(изображение взято отсюда, статья на русском языке)
Но хватит душной теории, давайте глянем ближе, как это вообще работает.
Предположим, мы хотим, чтобы когда 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#
и скриптов