Unity3d, Агенты и Танчики

    image

    Всем доброго времени суток!

    Еще в универе на старших курсах начал увлекаться интеллектуальными агентами. Даже тема для диплома изначально была связана с созданием агентов, участвующих в боевых действиях, в среде, имитирующей поле боя. Но из-за работы пришлось сменить тему.

    Давно хотел этим заняться, но все времени не было. Сейчас наконец-то дошли руки сделать среду для агентов, хотя и не в таком масштабе. Так что если кому-нибудь интересно, присоединяйтесь! Репозитарий открытый, ссылка внизу.

    Интеллектуальный агент.

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

    Схема простейшего агента, как говорит википедия, выглядит так:

    image

    У такого агента нет никакого разума, он действует исключительно по списку простейших правил if-then. Есть несколько видов гораздо более сложных агентов, которые умеют анализировать свои действия и обучаться. Но до них мне еще далеко.

    Unity3d

    Я создал в Unity3d проект, в котором есть поле боя (квадрат) и несколько танков. Текстуры танков я взял из старой-доброй игры Battle City. Все, что умеет каждый танк — это ездить по полю и стрелять.
    Так выглядит весь проект:

    image

    К каждому танку привязаны 2 управляющих скрипта:
    — TankBehavior
    — BasicTankControls (или его подкласс)

    TankBehavior — это главный скрипт, который полностью описывает один танк. В этом скрипте реализованы методы перемещения, стрельбы и все остальные. Также этот скрипт содержит ссылку на BasicTankControls, в котором реализовано управление танком. Базовый скрипт выглядит так:

    public class BasicTankControls : MonoBehaviour
    {
         public void Init(TankBehavior tank)
         {
              this.tank = tank;
         }
    
         public virtual void Act(List<TankData> tanksData)
         {
              // no operation
         }
    
         protected TankBehavior tank;
    }
    


    Так происходит инициализация скрипта-управления в скрипте TankBehavior:

    void Start ()
    {
         ...
         controls = GetComponent<BasicTankControls>();
         if(controls != null)
         {
              controls.Init(this);
         }
         ...
    }
    


    Этот метод вызывается каждый физический тик:

    void FixedUpdate()
    {
         if(controls != null)
         {
              GameObject[] tankObjects = GameObject.FindGameObjectsWithTag("Tank");
              List<TankData> tanksData = new List<TankData>();
    
              foreach (var item in tankObjects)
              {
                   if (item.GetInstanceID() != this.GetInstanceID())
                   {
                        tanksData.Add(item.GetComponent<TankBehavior>().GetData());
                   }
              }
    
              controls.Act(tanksData);
         }
    }
    


    Сначала собираются данные обо всех танках на поле. Таким образом имитируется сбор информации о среде датчиками агента. Затем эта информация передается скрипту-управлению, который уже на основе полученных данных будет оказывать воздействие на среду.
    Данные об одном танке выглядят так:

    public class TankData
    {
         public TankData(int instanceId, Vector2 position, float health, Direction direction)
         {
              this.InstanceID = instanceId;
              this.Position = position;
              this.Health = health;
              this.Direction = direction;
         }
    
         public readonly int InstanceID;
         public readonly Vector2 Position;
         public readonly float Health;
         public readonly Direction Direction;
    }
    


    Вот в принципе и все. Теперь задача состоит лишь в том, чтобы написать для танков управляющий скрипт. Я написал один скрипт для управления человеком, если вдруг кто-нибудь захочет вмешаться в ход событий:

    public class HumanControls : BasicTankControls
    {
         public override void Act(List<TankData> tanksData)
         {
              if(Input.GetButton("Up"))
              {
                   tank.MoveForward();
              }
              else if (Input.GetButton("Down"))
              {
                   tank.MoveBackward();
              }
    
              if (Input.GetButtonDown("Left"))
              {
                   tank.RotateLeft();
              }
              else if (Input.GetButtonDown("Right"))
              {
                   tank.RotateRight();
              }
    
              if (Input.GetButton("Fire"))
              {
                   tank.Fire();
              }
         }
    }
    

    Поведения танков

    Для начала планирую сделать простейшие автономные поведения, например ездить и стрелять в случайные стороны. Потом есть идея добавить стены (может быть, разрушаемые) и тот самый штаб, который одним нужно защищать, а другим разрушить. Может быть, даже будет совместное планирование действий.
    Но это очень оптимистичные планы. Сам еще такого никогда не писал, так что придется изучать. Любая помощь и советы приветствуются! :)

    Ссылка на репозитарий.
    Метки:
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 19
    • 0
      Не пойму, почему у Вас где-то сделана проверка на null при GetComponent, а местами нету.
      А в целом, интересная статья, почерпнул немного для себя ;)
      • 0
        Спасибо!
        Проверка на null стоит в тех местах, где идет получение компоненты BasicTankControls. А такой компоненты у объекта может и не быть, допустим, если танк стоит для красоты (когда тестировал выстрелы). RequireComponent здесь почему-то не работает, пытался.
        Объекты с тегом «Tank» подразумевают обязательное наличие TankBehavior, поэтому проверку не ставил. Тут полагаюсь на разработчика (себя).
        Понимаю, отмазка слабенькая, но проект на серьезность и не претендует :)
          • +1
            Отправилось рано. Не работает потому, что компонент уже висит на объекте. Если его удалить и повесить, то все зависимости будут повешены корректно и сама среда будет сопротивляться их удалению без удаления TankBehavior.
        • 0
          Изобретаем Scalatron под Unity?
          • 0
            Про этот проект не знал. Но я и на scala не программировал, и пока не собираюсь.
            Unity3d же была выбрана, т.к. здесь очень удобно реализовано управление объектами — через поведения. Когда в университете занимался агентами, мы использовали среду JADE, там агенты также управляются поведениями.
            • 0
              Так я же не с целью обидеть написал. Наоборот, сделать программируемый танко-дром на Юнити — это клёво.
              Популярность и низкий порог вхождения в C# в связке с возможностями по визуализации Unity3D может привлечь к вашему начинанию много энтузиастов.

              P.S. Scalatron — это всё же не совсем то. Robocode ближе к теме.
              • 0
                Да не, я и не обижался :)
                Насчет привлечения энтузиастов — очень надеюсь.
                А вот за Robocode большое спасибо! Обязательно его поковыряю.
        • +1
          Незакончено :(

          Что в итоге должно получиться? battle city? Чем данный метод (с агентами) отличается от других? (примернительно к играм)
          • 0
            Да, понимаю, что незакончено. Времени свободного не так много, как хотелось бы.
            В итоге (в идеале конечно) хотелось бы запустить и смотреть, как по полю боя ползают танки и пытаются друг друга уничтожить (или защитить / разрушить штаб).
            Не совсем уверен, что правильно понял вопрос про «чем отличается от других». Попытаюсь ответить, поправьте, если не прав.
            Обычно в играх (в том же Battle City) танки, ползающие по полю, действуют либо совсем случайным образом, либо по какому-нибудь примитивному алгоритму. Вот статья, примерно описывающая поведение ботов в игре. Сейчас конечно все сильно продвинулось, и есть игры с довольно неплохим ИИ. Данный метод как раз позволит узнать, как действует бот, какие модели поведения более / менее эффективные и т.д.
            Опять же, проект не претендует на серьезность, писал исключительно для себя. Решил поделиться, вдруг кому интересно будет.
          • +1
            Не поверите но я два месяца назад пытался сделать почти то же самое только платформа Tululoo Game Maker.
            В общем платформа кривая поэтому проект закрыл, но добавить интеллект танкам очень хотел, были тоже наполеоновские планы, чтобы противник окружал тебя, слышал если ты движешься недалеко от него…
            • 0
              Прекрасно вас понимаю :)
              • 0
                привет, ответь плиз в личке )
                • 0
                  Привет! ответил
            • +4
              GameObject[] tankObjects = GameObject.FindGameObjectsWithTag("Tank"); List<TankData> tanksData = new List<TankData>();

              Мне кажется, искать объекты по тегам и пересоздавать список танков каждый тик, да еще и для каждого агента — жестоко в плане производительности. Я бы подумал над способом кэширования этих данных.

              Конечно, обычно premature optimization не стоит того что бы тратить время, но тут уж очень в глаза бросилось :)
              • 0
                Да, спасибо. И правда толсто получилось :)
                Конечно, хранить список игроков надо в отдельной сущности. Нормальные люди так бы и сделали. Исправлюсь
                • 0
                  Ага. Какой-нит более-менее глобальный список пойдет.
              • 0
                Вспомнил сразу про старый добрый Террариум, поностальгировал.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.