Создание дерева поведения ИИ на C# — как?

Я пытаюсь создать "дерево поведения" с помощью С#.

Для тех, кто не знает, дерево поведения — это, по сути, структура, вокруг которой вы можете построить ИИ. Есть секвенсоры, селекторы, декораторы, составные действия и другие вещи.

Я нашел единственную библиотеку, в которой реализовано «дерево поведения» на C#, расположенное здесь (http://code.google.com/p/treesharp/), но я не могу понять, как его использовать, поскольку нет примера кода, который я мог бы использовать. Может ли кто-нибудь здесь сделать какой-нибудь простой пример кода, который показывает, как на самом деле использовать эту структуру ... или, возможно, вы знаете другой способ реализовать дерево поведения в C#?

Спасибо большое!


person Jason    schedule 22.11.2010    source источник
comment
Библиотека, которую вы упомянули на code.google.com, была добавлена ​​почти год назад и в последний раз обновлялась две недели спустя. Если вы планируете использовать ее, вы, вероятно, не найдете никаких примеров, возможно, будет лучше, если вы поищите другую библиотеку или разработаете свою собственную.   -  person tbridge    schedule 22.11.2010


Ответы (3)


Я только что посмотрел на эту реализацию, и мне стало интересно, зачем столько кода нужно для чего-то относительно простого.

Судя по тому, что вы говорите, вам нужен простой способ составления поведения. Я полагаю, что здесь поведение — это отображение состояния на ноль или более действий агента. Вы можете легко смоделировать это с помощью лямбда-выражений C#. Например:

Action Selector(Func<bool> cond, Action ifTrue, Action ifFalse) {
  return () => { if cond() then ifTrue() else ifFalse() };
}

Action Sequencer(Action a, Action b) {
  return () => { a(); b(); }
}

Листья вашего дерева — это простые Действия, которые делают что-то соответствующее состоянию. Вы "запускаете" дерево, просто выполняя его.

Если вы хотите пофантазировать, вы можете параметризовать эту схему, чтобы сделать состояние явным.

Надеюсь это поможет.

---- Дополнение ----

Джейсон попросил привести пример того, как вы можете использовать этот подход, поэтому вот простой пример патрулирования охранника с «ИИ» (я предполагаю, что WorldState соответствует описанию среды во время оценки дерева поведения):

Func<bool> ifPlayerIsInSight = () => ...true iff WorldState shows guard can see player...;

Action shootAtPlayer = () => { ...aim guard's weapon at player and fire... };

Func<bool> ifUnderFire = () => ...true iff WorldState shows guard hears player gunfire...;

Action takeCover = () => { ...guard runs for nearest shelter... };

Action walkBackAndForthGuardingDoorway = () => { ...default guard patrol behaviour... };

Action patrollingGuardBehaviour =
  Selector(ifPlayerIsInSight, shootAtPlayer,
    Selector(ifUnderFire, takeCover,
      walkBackAndForthGuardingDoorway));

Чтобы заставить охрану что-то сделать, достаточно позвонить patrollingGuardBehaviour(). Обратите внимание, что различные поддействия и тесты могут быть реализованы как методы с правильными сигнатурами, а не встроены как лямбда-выражения. К Selector и Sequencer можно добавить другие комбинаторы, например, для параллельной работы.

person Rafe    schedule 22.11.2010
comment
Рейф... деревья поведения на самом деле немного сложнее... позвольте мне попытаться объяснить их просто: дерево начинается с корня... и затем оттуда оно разветвляется на отдельные ветви логики. Каждая ветвь имеет фильтр, который решает, должен ли ИИ брать эту ветвь или нет. Существуют также секвенсоры, которые запускают последовательность действий, возвращаясь в случае неудачи любого действия, и селекторы, которые запускают действия до тех пор, пока не будет найден успех (игнорирует неудачи). Есть и другие вещи, но это суть. Можем ли мы как-нибудь поговорить об этом подробнее в чате? - person Jason; 22.11.2010
comment
Я просто очень запутался в том, как я мог на самом деле реализовать что-то подобное на С#... ваш пример действительно хорош, но... опять же, я не могу его понять. Может быть, для вашего внедрения вы могли бы написать небольшой пример, который показывал бы фактическое использование структуры? - person Jason; 22.11.2010
comment
Сначала вы строите дерево: вы определяете действия и когда (условия) и как (параллельно, последовательно и т. д.) они выполняются. Для простоты начните с дерева, которое всегда начинает выполнение с корневого узла и выбирает своих потомков в зависимости от текущих условий (сенсорный ввод). Есть много деталей реализации и улучшений, но это самый простой рабочий процесс. Вы уверены, что понимаете БТ как концепцию? Если нет, попробуйте aigamedev.com/insider/presentations/behavior-trees (требуется бесплатная регистрация) и их форумы. - person ftt; 22.11.2010
comment
Я довольно хорошо понимаю эту идею... это С# мешает, так как я все еще новичок в этом языке. :) Дерево в основном будет иметь много ветвей и подветвей... и под-подветвей и т.д.. так как я могу построить это с помощью С#? Вложенные циклы If и for each = не очень хорошая идея, верно? ха-ха :) Есть ли какой-нибудь пример кода, на который я мог бы посмотреть? С другими темами... обычно я учусь, изучая код других людей и наблюдая, как вещи взаимодействуют, одновременно читая о теме... какой-нибудь пример текста был бы отличным! :) - person Jason; 22.11.2010
comment
Рейф, можно ли как-нибудь напечатать краткий пример небольшого дерева, созданного с использованием лямбда и вашей структуры? - person Jason; 22.11.2010
comment
Если эта библиотека не включает какой-либо механизм для изучения этих деревьев, вся идея кажется мне неотличимой от базовой процедурной логики, написанной вручную. - person Cerin; 22.11.2010
comment
Крис С.: Я согласен, вы могли бы просто написать это как процедуры. Композиционный подход здесь позволяет на лету генерировать новые модели поведения. Что касается обучения поведению, это совсем другой вопрос. - person Rafe; 23.11.2010
comment
Да, вся идея деревьев поведения заключается в модульности. Вы используете справочные таблицы для базовых целей, чтобы выяснить, что нужно сделать для достижения этой цели, вместо того, чтобы строить настоящее массивное дерево. :) Раф, большое спасибо за дополнительный код. Супер полезно! - person Jason; 23.11.2010
comment
И просто для того, чтобы понять это прямо... в конце вашего кода вы сделали селектор... внутри селектора, верно? :) - person Jason; 23.11.2010

Похоже, что у одного из разработчиков TreeSharp, apocdev, есть некоторые код, который использует TreeSharp для какого-то игрока World of Warcraft, использующего заклинания.

Вот фрагмент:

public Composite CreateSpellCheckAndCast(string name)
{
    return new Decorator(
        ret => Spells.CanCast(name),
        new Action(ret => Spells.Cast(name)));
}

Я не уверен, но использование здесь кажется довольно простым: класс Decorator выглядит так, как будто он проверяет предикат (Spells.CanCast) перед попыткой выполнить какое-то действие (Spells.Cast).

Таким образом, Composite, возможно, является Action, который может делать несколько вещей, например. предварительно проверить предикат или выполнить несколько действий последовательно.

блог apocdev упоминает этот обзор деревьев поведения со ссылками на более общие описания последовательности, селекторы и декораторы.

person Nate Kohl    schedule 22.11.2010
comment
похоже, что большинство ссылок на этот ответ не работают :( - person roundcrisis; 03.10.2013
comment
@Miau: Да, похоже, что блог apocdev не работает. Ссылки пока оставлю, вдруг появится в ближайшее время. - person Nate Kohl; 03.10.2013

Лямбда-выражения С# становятся дорогими, когда они включают замыкания, поскольку это приведет к выделению памяти на каждом кадре/итерации вашего BT. Вы можете избежать закрытия с помощью доски, но есть более простой подход.

Вы можете реализовать деревья поведения, используя сокращенные условные операторы && и ||. Этот подход проиллюстрирован здесь: https://github.com/eelstork

Тогда пример патруля будет выглядеть так:

Status Patrol()
    => (playerInSight && Shoot(player)) 
    || (underFire && TakeCover())
    || GuardDoorway();
person Tea    schedule 28.11.2020