Как агенты ИИ получают доступ к информации о своей среде?

9

Это может быть своего рода тривиальный вопрос, но у меня возникают проблемы с пониманием этого. Буду очень признателен за вашу помощь.

В разработке игр с использованием объектно-ориентированного дизайна я хочу понять, как AI-агенты получают доступ к информации, которая им нужна из игрового мира для выполнения своих действий.

Как мы все знаем, в играх очень часто агентам ИИ нужно «воспринимать свое окружение» и действовать в соответствии с тем, что происходит вокруг них. Например, агент может быть запрограммирован, чтобы преследовать игрока, если он / она приближается достаточно близко, избегать препятствий во время движения (используя поведение поворота для предотвращения препятствий) и т. Д.

Моя проблема в том, что я не уверен, как это сделать. Как агент ИИ может получить доступ к необходимой информации об игровом мире?

Один из возможных подходов заключается в том, что агенты просто запрашивают необходимую информацию непосредственно из игрового мира.

Есть класс под названием GameWorld. Он обрабатывает важную игровую логику (игровой цикл, обнаружение столкновений и т. Д.), А также содержит ссылки на все объекты в игре.

Я мог бы сделать этот класс Singleton. Когда агенту нужна информация из игрового мира, он просто получает ее непосредственно из экземпляра GameWorld.

Например, агент может быть запрограммирован Seekна игрока, когда он / она близко. Для этого агент должен получить позицию игрока. Таким образом, можно просто запросить его непосредственно: GameWorld.instance().getPlayerPosition().

Агент также может просто получить список всех сущностей в игре и проанализировать его на предмет его потребностей (чтобы выяснить, какие сущности находятся рядом или что-то еще): GameWorld.instance().getEntityList()

Это самый простой подход: агенты напрямую связываются с классом GameWorld и получают необходимую им информацию. Тем не менее, это единственный подход, который я знаю. есть ли лучший?

Как опытный разработчик игр разработает это? Является ли наивный подход «получить список всех сущностей и найти все, что вам нужно»? Какие существуют подходы и механизмы, позволяющие агентам ИИ получать доступ к информации, которая им необходима для выполнения их действий?

Авив Кон
источник
Если у вас есть доступ к подписке на GDCVault, в 2013 году состоялась отличная беседа под названием «Создание ИИ для живого, дышащего мира Абсолюта Хитмана», в которой подробно рассматривается их модель знаний ИИ.
DMGregory

Ответы:

5

То, что вы описываете - это классическая модель запросов мира. В большинстве случаев это работает довольно хорошо, особенно для игр с базовым ИИ (а это больше всего). Тем не менее, есть несколько моментов , вы должны учитывать , что может быть отрицательные стороны:

  • Вы, вероятно, хотите удвоить буфер. См. Шаблоны программирования игр на эту тему . Всегда запрашивая данные напрямую из мира, вы можете получить странные условия гонки, в которых результат зависит от того, в каком порядке вызван ИИ. Важно ли это для вашей игры, решать вам. Одним из возможных результатов является то, что он смещает игру к тому, кто идет «первым» или «последним», делая многопользовательскую игру несправедливой.

  • Часто пакетные запросы могут быть намного эффективнее, особенно для определенных структур данных. Здесь вы можете сделать так, чтобы каждый агент ИИ, который хочет искать препятствия, создал «объект запроса» и зарегистрировал его в единственном центральном препятствии. Затем, перед основным циклом AI, все запросы выполняются к структуре данных, которая сохраняет структуру данных препятствий в кеше. Затем во время AI-части каждый агент обрабатывает результаты своего запроса, но ему не разрешается делать напрямую. В конце кадра объекты AI обновляют запросы с учетом их нового местоположения или добавляют или удаляют их. Это похоже на ориентированный на данные дизайн .

    Обратите внимание, что это в основном делает двойную буферизацию, сохраняя результат запросов в буфере. Это также требует от вас предвидеть, нужно ли вам делать запрос во фрейме раньше. Это модель «push», потому что агенты объявляют, какие обновления им интересны (путем создания соответствующего объекта запроса), и эти обновления передаются им. Обратите внимание, что вы также можете иметь объект запроса, содержащий обратный вызов, а не хранить все результаты для фрейма.

  • Наконец, вы, вероятно, захотите использовать интерфейсы или компоненты для объектов поиска, а не наследования, что хорошо описано в других местах. Перебор списка Entitiesпроверок instanceOf- это, вероятно, рецепт довольно хрупкого кода, минуты, когда вы хотите, чтобы и то, StaticObjectи другое MovingObjectбыло Healable. (если не instanceOfработает для интерфейсов на выбранном вами языке.)


источник
5

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

Чтобы облегчить вашу заботу о моделях доступа к данным, давайте рассмотрим несколько различных примеров ИИ как в игровой индустрии, так и за ее пределами, исходя из того, что далеко от навигации человеком, до того, что нам наиболее знакомо.

(Каждый пример предполагает одно глобальное обновление логики.)

  • * Кратчайший путьКаждый ИИ рассчитывает состояние карты для целей поиска пути. A * требует, чтобы каждый ИИ уже знал всю (локальную) среду, в которой он должен найти путь, поэтому мы должны передать ему информацию о препятствиях на карте и пространстве (часто это двухмерный логический массив). A * - это специализированная форма алгоритма Дейкстры, алгоритма поиска по кратчайшему пути с открытым графом; такие подходы возвращают списки, представляющие путь, и на каждом шаге ИИ просто выбирает следующий узел в этом списке, к которому нужно перейти, пока он не достигнет своей цели или не потребуется пересчет (например, из-за изменения препятствий на карте). Без этого знания невозможно найти реалистичный кратчайший путь. A * - вот почему ИИ в играх RTS всегда знают, как добраться из точки A в точку B - если путь существует. Он пересчитает кратчайший путь для каждого отдельного ИИ, потому что валидность пути основана на положении тех ИИ, которые ранее переместились (и потенциально заблокировали определенные пути). Итерационный процесс, посредством которого A * вычисляет значения ячеек во время поиска пути, является одним из математической конвергенции. Можно сказать, что конечный результат напоминает обоняние, смешанное с чувством зрения, но в целом оно несколько чуждо нашему мышлению.

  • Совместная диффузия Также встречается в играх, это больше всего напоминает обоняние, основанное на диффузии газов и частиц. Компакт-диск решает проблему дорогостоящей повторной обработки, найденной в A *: вместо этого сохраняется единственное состояние карты, которое обрабатывается один раз за обновление для всех ИИ, а затем к результатам обращается каждый ИИ по очереди, чтобы он сделал свой соответствующий ход. , Больше не один путь (список ячеек), возвращаемый алгоритмом поиска; скорее, каждый ИИ будет проверять карту после ее обработки и перемещаться в любую соседнюю ячейку, имеющую наибольшее значение. Это называется восхождение на гору . Тем не менее, этап обработки карты уже должениметь предварительный доступ к информации карты, которая также содержит информацию о местонахождении всех тел ИИ. Следовательно, карта ссылается на AI, а затем AI ссылается на карту.

  • Компьютерное зрение и лучевое вещание + кратчайший путь В робототехнике с марсоходом и дроном это становится нормой для определения размеров пространства, в котором перемещается робот. Это позволяет роботам построить полную объемную модель своего окружения, так же как мы могли бы видеть или даже слышать или слышать (для слепых или глухих), которую робот затем может свести к минимальному топографическому графику (немного похожему на график путевых точек используется в играх с A *), к которым затем могут применяться алгоритмы кратчайшего пути. В этом случае, хотя «видение» может дать ключ к непосредственному окружению, оно все же приводит кпоиск по графику, который в конечном итоге обеспечивает путь к цели. Это близко к человеческой мысли: чтобы добраться до кухни из спальни, я должен пройти через гостиную. Тот факт, что я уже видел их и знаю их места и порталы, это то, что делает возможным этот просчитанный ход. Это топология графа, к которой применяется алгоритм кратчайшего пути, хотя и встроенный в мягкий белок, а не в твердый кремний.

Таким образом, вы можете видеть, что первые два зависят от того, что вы уже знаете окружающую среду целиком. По причинам стоимости оценки среды с нуля, это часто встречается в играх. Понятно, что последний самый мощный. Оборудованный таким образом робот (или, например, игровой ИИ, который считывает буфер глубины для каждого кадра), может достаточно ориентироваться в любой среде без предварительного знания этого. Как вы, наверное, догадались, это также безусловно самый дорогой из трех вышеперечисленных подходов, и в играх мы обычно не можем позволить себе делать это для каждого AI. Конечно, в 2D это намного дешевле, чем в 3D.

Архитектурные точки

Выше становится ясно, что мы не можем предположить только один правильный шаблон доступа к данным для ИИ; Выбор зависит от того, чего вы пытаетесь достичь. Прямой доступ к GameWorldклассу абсолютно стандартен: он просто предоставляет вам информацию о мире. По сути, это ваша модель данных, и именно для этого нужны модели данных. Синглтон подходит для этого.

«получить список всех сущностей и найти все, что вам нужно»

В этом нет ничего наивного. Единственное, что может быть наивным, - выполнять больше итераций списка, чем нужно. При обнаружении столкновений мы избегаем этого, используя, например, квадродерево, чтобы уменьшить пространство поиска. Подобные механизмы могут применяться к ИИ. И если вы можете использовать один и тот же цикл для выполнения нескольких задач, сделайте это, потому что ветки стоят дорого.

инженер
источник
Спасибо за ответы. Поскольку я новичок в разработке игр, я думаю, что пока придерживаюсь простого подхода «получить список из игрового мира» :) Один вопрос: в своем вопросе я описал GameWorldкласс как класс, содержащий ссылки на все игровые объекты, а также содержит большую часть важной логики «движка»: основной игровой цикл, обнаружение столкновений и т. д. Это в основном «основной класс» игры. Мой вопрос: распространен ли такой подход в играх? Есть «основной класс»? Или я должен разделить его на более мелкие классы и иметь один класс, который могут опрашивать объекты «базы данных сущностей»?
Авив Кон
@Prog Не за что. Опять же, ничто в вышеупомянутых подходах ИИ (или любых других, если на то пошло) не предполагает, что ваше «получение списка из игрового мира» является каким-либо способом, формой или формально неправильным с точки зрения архитектуры. Архитектура ИИ должна соответствовать потребностям ИИ; но эта логика, как вы предлагаете, должна быть модульной, инкапсулированной (в своем собственном классе) вне вашей более широкой архитектуры приложения. Да, подсистемы всегда должны быть разбиты на отдельные модули, когда такие вопросы возникают. Ваш руководящий принцип должен быть SRP .
инженер
2

По сути, у меня есть 2 способа запроса информации.

  1. когда состояние AIState изменяется, потому что вы обнаружили столкновение или что-то еще в кеше, ссылка на любой важный объект. Таким образом, вы знаете, какая ссылка вам нужна. Когда другие системы вынуждены выполнять большой поиск в каждом кадре, я бы порекомендовал копировать их, чтобы вам не приходилось выполнять многократный поиск. Таким образом, «столкновение», обнаруженное с зоной, которая заставляет врага «предупреждать», отправляет ему сообщение / событие, которое регистрирует его с этим объектом, если он еще не существует, и изменяет игровое состояние на то, которое заставляет его заниматься своими делами, основываясь на том, что он находится в это состояние игры. Вам нужно событие какого-то типа, которое скажет вам внести изменения, я просто передам ссылку на любой обратный вызов, который вы используете для предоставления этой информации. Это более продолжительно, чем просто иметь дело с игроком. Может быть, вы хотите, чтобы враг преследовал другого врага или какой-то другой объект. Таким образом, вам нужно всего лишь изменить любой тег, по которому вы его идентифицируете.

  2. С этой информацией вы затем выполните запрос к системе поиска пути, которая использует A * или какой-либо другой алгоритм, чтобы дать вам путь, или вы можете использовать его с некоторым поведением рулевого управления. Может быть, сочетание того или другого. По сути, с преобразованием обоих вы должны иметь возможность запрашивать систему узлов или навигационную систему, и она дает вам путь. В вашем игровом мире, вероятно, есть много других вещей, кроме поиска пути. Я бы отправил ваш запрос только на поиск пути. Кроме того, пакетирование этих вещей, вероятно, лучше всего, если у вас много запросов, потому что это может быть довольно интенсивным, а пакетная обработка поможет повысить производительность.

    Transform* targetTransform = nullptr;
    EnemyAIState  AIState = EnemyAIState::Idle;
    void OnTriggerEnter(GameObject* go)
    {
       if(go->hasTag(TAG_PLAYER))
       {
       //Cache important information that will be needed during pursuit
       targetTransform = go->getComponent<Transform>();
       AIState = EnemyAIState::Pursue;
       }
    }
    
    void Update()
    {
       switch(AIState)
       {
          case EnemyAIState::Pursue:
           //Find position to move to
           Vector3 nextNode = PathSystem::Seek(
                              transform->position,targetTransform->position);
           /*Update the position towards the target by whatever speed the unit moves
             Depending on how robust your path system is you might want to raycast
             against obstacles it can't take into account or might clip the path.*/
            transform->Move((nextNode - transform->position).unitVector()*speed*Time::deltaTime());
            break;
        }
     }
    
user2927848
источник