Игровой AI: шаблон для реализации компонентов Sense-Think-Act? - PullRequest
1 голос
/ 20 апреля 2010

Я занимаюсь разработкой игры. Каждая сущность в игре - это GameObject. Каждый GameObject состоит из GameObjectController, GameObjectModel и GameObjectView. (Или его наследники.)

Для NPC GameObjectController делится на:

IThinkNPC: читает текущее состояние и принимает решение о том, что делать

IActNPC: обновляет состояние в зависимости от того, что нужно сделать

ISenseNPC: считывает текущее состояние для ответа на мировые запросы (например, "я в тени?")

Мой вопрос: это нормально для интерфейса ISenseNPC?

public interface ISenseNPC
    {
        // ...

        /// <summary>
        /// True if `dest` is a safe point to which to retreat.
        /// </summary>
        /// <param name="dest"></param>
        /// <param name="angleToThreat"></param>
        /// <param name="range"></param>
        /// <returns></returns>
        bool IsSafeToRetreat(Vector2 dest, float angleToThreat, float range);

        /// <summary>
        /// Finds a new location to which to retreat.
        /// </summary>
        /// <param name="angleToThreat"></param>
        /// <returns></returns>
        Vector2 newRetreatDest(float angleToThreat);

        /// <summary>
        /// Returns the closest LightSource that illuminates the NPC.
        /// Null if the NPC is not illuminated.
        /// </summary>
        /// <returns></returns>
        ILightSource ClosestIlluminatingLight();

        /// <summary>
        /// True if the NPC is sufficiently far away from target.
        /// Assumes that target is the only entity it could ever run from.
        /// </summary>
        /// <returns></returns>
        bool IsSafeFromTarget();
    }

Ни один из методов не принимает никаких параметров. Вместо этого реализация должна поддерживать ссылку на соответствующий GameObjectController и читать его.

Однако сейчас я пытаюсь написать модульные тесты для этого. Очевидно, что нужно использовать насмешку, поскольку я не могу передавать аргументы напрямую. То, как я это делаю, кажется действительно хрупким - что, если придет другая реализация, которая использует утилиты запросов по-другому? На самом деле, я не тестирую интерфейс, я тестирую реализацию. Плохо.

Причина, по которой я использовал этот шаблон в первую очередь, заключалась в том, чтобы поддерживать чистоту IThinkNPC кода реализации:

    public BehaviorState RetreatTransition(BehaviorState currentBehavior)
    {
        if (sense.IsCollidingWithTarget())
        {
            NPCUtils.TraceTransitionIfNeeded(ToString(), BehaviorState.ATTACK.ToString(), "is colliding with target");
            return BehaviorState.ATTACK;
        }

        if (sense.IsSafeFromTarget() && sense.ClosestIlluminatingLight() == null)
        {
            return BehaviorState.WANDER;
        }

        if (sense.ClosestIlluminatingLight() != null && sense.SeesTarget())
        {
            NPCUtils.TraceTransitionIfNeeded(ToString(), BehaviorState.ATTACK.ToString(), "collides with target");
            return BehaviorState.CHASE;
        }
        return currentBehavior;
    }

Возможно, чистота того не стоит.

Итак, если ISenseNPC принимает все необходимые параметры каждый раз, я мог бы сделать это статическим. Есть ли с этим проблемы?

1 Ответ

2 голосов
/ 12 апреля 2011

NO. Нет нет нет. Вы создаете нелепое количество скрытых (и не скрытых) зависимостей в своем ИИ. Во-первых, MVC здесь не совсем подходит для использования, так как на самом деле нет «представления», о котором вам нужно заботиться, есть только действия. Кроме того, ваша «модель» - это действительно состояние мира, известное ИИ в то время, которое полностью отделено от самого ИИ, хотя это можно рассматривать как «представление» игрового мира с точки зрения снимок позиций и атрибутов вашего объекта (я сделал это таким образом, был очень эффективен).

Однако основная проблема заключается в том, что ваш код retreatTransition тесно связан с действиями и состоянием. Что бы произошло, если бы вам пришлось внести изменения? Что, если вам нужно 200 разных типов ИИ, которые все похожи, как бы вы поддерживали это? Ответ в том, что вы не можете, это будет беспорядок. Вы эффективно создаете конечный автомат, и конечные автоматы плохо масштабируются. Кроме того, вы не можете добавить / изменить / удалить состояние с вашего компьютера без редактирования кода.

Вместо этого я бы порекомендовал перейти на другую архитектуру. Ваш подход к TDD здесь великолепен, однако вам нужно сделать шаг назад, посмотреть на различные архитектуры ИИ и понять основные концепции, прежде чем сделать выбор. Я бы начал с рассмотрения превосходной статьи Джеффа Оркина «3 состояния и план», в которой рассказывается о целенаправленной архитектуре Ф.Э.А.Р. (http://web.media.mit.edu/~jorkin/goap.html). Я реализовал это раньше, и это было очень эффективно и глупо легко проектировать и обслуживать. Его основной дизайн также облегчил бы TDD (фактически BDD - лучший выбор) довольно хорошо.

Другое дело: ваш ISenseNPC выглядит так, как будто он тесно связан с мировым состоянием. Восприятие вашего ИИ (вещи, которые он может наблюдать из мира) должно быть совершенно отдельным, так что это говорит мне, что у вас должен быть класс WorldModel или что-то, что передается в объект ISenseNPC, который затем проверяет WorldModel на предмет релевантности информацию через ее восприятия (воспринимайте восприятие как способ, которым ИИ может воспринимать мир, что-то вроде датчика, радиуса зрения, сонара и т. д.), а затем вы даже можете создавать отдельные восприятия и добавлять их в свой ISenseNPC, который будет разъединять состояние мира, то, как ИИ воспринимает этот мир, а затем понимание ИИ самого мира. Оттуда ваш ИИ может принимать решения о том, что он должен делать.

Вы моделируете простой рефлекторный агент, который представляет собой просто набор правил, отвечающих заданной последовательности восприятия, что хорошо для простого ИИ. По сути, это прославленный конечный автомат, однако затем вы можете создать сопоставление восприятий с поведением в вашем объекте Think, которое можно поддерживать отдельно, и изменение этого сопоставления или его расширение не потребует изменения кода (принцип единой ответственности в работе). Кроме того, вы можете создать игровой редактор, который может перечислять все восприятия, решения и действия и связывать их вместе для любого данного ИИ, что облегчит вам поддержку ваших ИИ без необходимости даже заходить в игру или даже перестраивать код (потенциально) , Я думаю, вы найдете это гораздо более гибким и обслуживаемым, чем то, что вы пытаетесь сделать здесь. Полагаю, что MVC для этой конкретной вещи, MVC очень подходит для графики и, в меньшей степени, для физики, но на самом деле он не очень хорошо подходит для ИИ, так как у ИИ нет «вида».

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

...