Написание ИИ для хоккея. Часть 1

hockey-ai

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

Ключевым моментом будет использование рулевого поведения (steering behaviors), о котором я рассказывал в одной из своих прошлых статей (рассказ от лица автора — прим. переводчика).

Примечание Несмотря на то, что эти уроки написаны с использованием Action Script 3 и Flash, вам не должно составить труда реализовать игру в любой другой среде разработки на любом языке программирования.

Введение

Хоккей — одна из самых популярных спортивных игр. О нем написано множество статей, охватывающих и тактику игры, и поведение игроков в атаке и в защите, и такую тонкую вещь, как работа в команде. И, разумеется, искусственный интеллект. Реализация хоккея отлично подходит для демонстрации сочетания некоторых полезных приемов и методов.

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

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

Обзор предстоящей работы

Как уже говорилось выше, хоккей — очень сложная игра. В ней присутствует огромное количество правил, нарушений и т.д. Для сокращения времени обучения, мы несколько упростим игру и сохраним лишь небольшой набор оригинальных правил этого вида спорта: у нас не будет вратарей (все игроки на катке будут двигаться), а также мы не будем учитывать всевозможные штрафы.

Так будет выглядеть наша игра

Так будет выглядеть наша игра

Ворота в нашей игре тоже будут своеобразные — сетка будет отсутствовать, а для того, чтобы забить гол, достаточно шайбе коснуться «ворот» с любой стороны. После забитого гола все игроки встают на свои позиции, шайба перемещается в центр, и через несколько секунд игра начинается заново.

Касаемо обработки шайбы: если игрок А находится с шайбой, а игрок B сталкивается с ним, то шайба переходит к игроку B, который становится недвижимым на некоторое время.

Для вывода графики я буду использовать графический движок Flixel. Однако в прилагаемом коде я буду опускать все связанное с графикой и максимально обращать ваше внимание на механику игры.

Базовые классы

Давайте начнем с основ — катка, который представляет собой прямоугольник, игроков и двух ворот. Каток имеет физические границы, поэтому ничего не выйдет за пределы поля. Хоккеист будет описываться классом Athlete:

Поле mBoid является объектом класса Boid, более подробно о котором вы можете прочитать в серии уроков про рулевое поведение. Он имеет, среди прочих элементов, вектор направления, вектор силы, а также текущее положение игрока.

Метод update() будет вызываться каждый раз, пока запущена игра. Сейчас в этом методе очищается любое активное усилие в рулевом поведении, добавляется эффект блуждания игрока, а также вызывается метод mBoid.update().

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

Если мы добавим одного хоккеиста на поле, то увидим такой результат:

 

 

 

Следуй за мышью

Мышь имеет координаты на экране, а потому мы можем использовать их в качестве пункта назначения для игрока. Мы можем использовать метод arrival объекта mBoid. Он задает цель, которую будет преследовать игрок. Движение будет плавным, а по мере приближения скорость хоккеиста будет падать и, в конце концов, станет равна 0.

Давайте заменим блуждающий метод в классе Athlete на движение к курсору мыши:

В результате мы получим возможность управлять нашим игроком мышью, а движение получится плавным и реалистичным:

 

 

 

Добавим шайбу

Шайба будет описываться классом Puck. Самое важное здесь — метод update() и поле mOwner.

Следуя той же логике, что и выше, метод update() будет выполняться каждый раз, пока запущена игра. Поле mOwner будет хранить того хоккеиста, который владеет шайбой. Если же mOwner равно null, то шайба никому не принадлежит и она свободно скользит по катку.

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

Ставим шайбу перед ее владельцем

А вот и код:

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

 

 

 

Удар по шайбе

Реализуем удар по шайбе клюшкой. Независимо от того, кто является владельцем шайбы, нам нужно сымитировать удар по ней и вычислить направление этого удара. Затем отправить шайбу по найденному вектору. Вычислить этот вектор несложно:

Вычисление вектора удара

А вот и реализация удара по шайбе:

В классе PlayState метод goFromStickHit() выполняется каждый раз, когда игрок нажимаете на экран. Координата клика используется в качестве конечной точки для удара. Результат виден ниже:

 

 

 

Добавление ИИ

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

Для этого мы будем использовать конечный автомат (FSM — finite state machine). Как было написано ранее, FSM является универсальным и полезным инструментом для реализации ИИ в играх.

Немного изменим наш класс Athlete:

Поле mBrain является экземпляром класса StackFSM, о котором более подробно вы можете узнать из этой статьи. Он использует стек для управления состоянием ИИ. Каждое состояние описывается методом, и, когда состояние кладется в стек, оно становится активным и вызывается каждый раз при вызове основного метода update().

Все состояния игрока будут выполнять строго определенную функцию: взять шайбу, отобрать шайбу, патрулировать зону и т.д.

Теперь хоккеист может быть как под нашим контролем, так и под контролем ИИ. Обновим наш класс:

Если хоккеист находится под контролем искусственного интеллекта, то мы обновляем ее логику, вызывая mBrain.update(). Если же хоккеист под управлением игрока, то логика ИИ игнорируется, а спортсмен следует за мышью.

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

Состояние покоя

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

Метод stopAndlookAt() высчитывает нужное направление по тому же алгоритму, по которому мы вычисляли направление удара. Вектор, начинающийся с позиции хоккеиста и заканчивающийся позицией шайбы, измеряется по формуле thePoint - mBoid.position и используется для указания направления взгляда спортсмена.

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

Подготовка к матчу

Это состояние ответственно за то, чтобы игроки возвращались на свои позиции и останавливались там. Обновим наш класс Athlete:

Ниже вы сможете увидеть результат добавления ИИ в игру. Нажмите клавишу G и игроки переместятся в случайные позиции. Затем они встанут на нужные места:

 

 

 

Вывод

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

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

Перевод статьи «Create a Hockey Game AI Using Steering Behaviors: Foundation»