Space Turret: Defense Point - Часть 5. Игровой ИИ и с чего начать

Всем привет!

С чего начинается искусственный интеллект (ИИ)? А начинается он с объекта, которым ИИ будет управлять. В зависимости от того, как Вы спроектируете свой объект, будет зависеть сложность его управления.

Мы с самого начала разделили наши объекты на разрушаемые и неразрушаемые. Для разрушаемых объектов сделали простой скрипт Health, который позволял задавать Жизнь и имел функцию AddDamage(float damage), через которую наносился урон объекту. Если у объекта заканчивалась Жизнь, он деактивировался.


Противники у нас разрушаемые, но кроме параметра Жизнь, им нужны были еще параметры  Скорость передвижения, Скорость поворота, Наносимый урон, Дальность атаки и Точность попадания. И еще Уровень противника, от которого будут зависеть некоторые показатели.

Поэтому, на базе скрипта Health мы сделали новый скрипт SpaceShip, в котором мы могли хранить такие настройки.


Пример настройки фрегата

Space Turret: Defense Point - Часть 5. Игровой ИИ и с чего начать Мобильные игры, Gamedev, Игры на Android, Шутер, Онлайн-шутер, Unity, Видео, Длиннопост

Для чего нужно наследоваться от класса Health?

В игре есть пули, ракеты и лазеры, которые при попадании наносят урон. Так как у нас только один класс отвечает за разрушаемость, то нам достаточно проверить, есть ли скрипт Health у объекта, куда попала пуля. И если есть - нанести урон.


Сейчас хочу сказать, что общая структура противников получилась очень удобной и понятной. Если нам нужны были какие то дополнительные параметры для корабля, то мы уже создавали новый класс на базе SpaceShip (например, для авианосца нужна ссылка на объект-истребитель, а также два параметра - лимит истребителей и задержка между их запуском). Параметры корабля инициализировались в скрипте Генератора противников, перед выходом корабля из варпа.

Ну что, теперь у нас уже есть некоторые параметры для нашего ИИ.


На чем сделать ИИ?

Изначально, я очень хотел сделать ИИ на базе нейронных сетей, чтобы корабли сами выстраивали свою стратегию полета, уклонялись от снарядов и вообще, становились сильнее с каждой игрой. К сожалению, мне не хватило знаний, чтобы формализовать и перенести такие действия на нейронные сети. Хотя как работают нейронные сети и как проводить их обучение - я знаю :)

Раз нейронные сети отпадают, то оставался вариант - машина состояний (state machine). Такой вариант хорошо вписывался в общую концепцию поведения кораблей, потому что любое поведение кораблей можно было разделить на составляющие - подлететь к базе, отлететь от базы, приблизиться на определенную дистанцию, лететь к выбранной точке А, повернуться стороной и т.д.


Визуализация двух состояний истребителя

Space Turret: Defense Point - Часть 5. Игровой ИИ и с чего начать Мобильные игры, Gamedev, Игры на Android, Шутер, Онлайн-шутер, Unity, Видео, Длиннопост

Оставалось выбрать, как реализовать машину состояний:

1. писать свой "движок" для состояний;

2. использовать какой то готовый "движок".


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

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

Получается, мы можем писать логику ИИ практически без всякой нагрузки на главный процесс игры! Это же какая оптимизация получается! :) Только при разработке кода, нужно учитывать, что код выполняется параллельно, и если мы будем менять какие то общие переменные, то нужно делать это безопасно, с использованием блокировок.


Состояния аниматора Unity

Чтобы использовать код в состояниях, нужно написать скрипт, который наследуется от класса StateMachineBehaviour. Мы постарались сделать некий удобный шаблон, который использовали во всех подобных скриптах.


public class StateTemplate : StateMachineBehaviour
{
[Header("Parameters")]
//тут можно объявить всякие параметры
[Header("State settings")]
public string onExitDeactivate = "stateA";
public string onFinishActivate = "stateB";  //приватные переменные

public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)

{
//вызывается при каждом входе в состояние
//через animator.GetComponent можно получить доступ к скриптам объекта
}
public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
//пока состояние активно, постоянно вызывается
//если нужно выйти из состояния, вызываем animator.SetBool(onFinishActivate, true);
}
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
//вызывается при каждом выходе из состояния
animator.SetBool(onExitDeactivate, false);
}
}
Каждое состояние у нас связано с определенной переменной типа bool в аниматоре.
Когда нам нужно выйти из состояния А, мы активируем переменную stateB, и у нас состояние переходит в состояние B. При этом, переменная stateA сразу деактивируется. Функция OnStateUpdate вызывается либо каждый кадр, либо каждый "физический тик", в зависимости от настроек аниматора.

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

Также важно учесть, что внутри функций нельзя объявлять переменные, иначе при параллельной работе значения будут перезатираться. Все переменные объявляются как атрибуты класса и будут принадлежать одному противнику (владельцу аниматора). Это особенность аниматора Unity.


Разработка ИИ

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

1. Истребители будут иметь два состояния - в одном состоянии они приближаются к станции на определенную дистанцию, а потом переходят во второе состояние и отлетают в случайном направлении и потом всё повторяется.

2. Фрегаты также имеют два состояния, сначала они приближаются к станции на некоторую дистанцию, а потом переходят во второе состояние, где летают влево-вправо перед станцией.

3. Крейсеры и Авианосцы также имеют два состояния - подлетают к станции и после этого поворачиваются одной из сторон к станции и открывают огонь.


В дальнейшем, мы улучшили поведение истребителей. Потому что изначально, каждый из них летал самостоятельно, кто то нападал, другой в это время отлетал. Получалось какое то месиво. Этот тип кораблей стал самым ненавистным в игре :) Мы хотели их как то сгруппировать, чтобы игроку было удобнее и зрелищнее их уничтожать. И тут мне попадается статья о симуляции полета стаи птиц под названием Boids. Увидев эту симуляцию, мы просто загорелись желанием реализовать подобное поведение у истребителей! Через несколько вечеров доработка была готова!

Теперь каждый истребитель присваивался группе. "Голова" группы выбирал куда лететь - на станцию или от станции, все остальные члены группы следовали за ним с помощью алгоритма Boids.


Состояния ИИ истребителя

Space Turret: Defense Point - Часть 5. Игровой ИИ и с чего начать Мобильные игры, Gamedev, Игры на Android, Шутер, Онлайн-шутер, Unity, Видео, Длиннопост

Теперь у истребителей было три состояния:

1. Boids - если истребитель не "голова" группы, он остается в этом состоянии. Здесь происходит расчет движения корабля в стае. В случае, если текущая "голова" группы будет уничтожена, следующий за ним в группе корабль становится новой "головой" группы.

2. Fly Back - это состояние для "головы" группы, истребитель выбирает случайное направление и удаляется от станции.

3. Chase - это также состояние для "головы" группы, истребитель приближается к станции.


Демонстрация нового ИИ истребителей

Результаты оказались просто потрясающими! Новое поведение истребителей стало гораздо зрелищнее и приятнее :)


Если кому то будет интересно, как именно писать код для состояний, то вот пример скрипта, который случайно поворачивает Крейсер влево или вправо и открывает стрельбу по игроку NetRotateSide.cs


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

В следующей статье я расскажу о том, как мы делали локализацию.

Если у Вас есть идеи поведения противников - делитесь!

Всем хорошего кодинга!


Предыдущие статьи:

Часть 4. Противники (продолжение)

Часть 3. Противники

Часть 2. Генератор волн противников

Часть 1. История разработки


Ссылка игры в Google Play: Space Turret: Defense Point

Лига Разработчиков Видеоигр

6.8K постов22.2K подписчиков

Добавить пост

Правила сообщества

ОБЩИЕ ПРАВИЛА:

- Уважайте чужой труд и используйте конструктивную критику

- Не занимайтесь саморекламой, пишите качественные и интересные посты

- Никакой политики


СТОИТ ПУБЛИКОВАТЬ:

- Посты о Вашей игре с историей её разработки и описанием полученного опыта

- Обучающие материалы, туториалы

- Интервью с опытными разработчиками

- Анонсы бесплатных мероприятий для разработчиков и истории их посещения;
- Ваши работы, если Вы художник/композитор и хотите поделиться ими на безвозмездной основе

НЕ СТОИТ ПУБЛИКОВАТЬ:

- Посты, содержащие только вопрос или просьбу помочь
- Посты, содержащие только идею игры

- Посты, единственная цель которых - набор команды для разработки игры

- Посты, не относящиеся к тематике сообщества

Подобные посты по решению администрации могут быть перемещены из сообщества в общую ленту.

ЗАПРЕЩЕНО:

- Публиковать бессодержательные посты с рекламой Вашего проекта (см. следующий пункт), а также все прочие посты, содержащие рекламу/рекламные интеграции

- Выдавать чужой труд за свой

Подобные посты будут перемещены из сообщества в общую ленту, а их авторы по решению администрации могут быть внесены в игнор-лист сообщества.


О РАЗМЕЩЕНИИ ССЫЛОК:

Ссылка на сторонний ресурс, связанный с игрой, допускается только при следующих условиях:

- Пост должен быть содержательным и интересным для пользователей, нести пользу для сообщества

- Ссылка должна размещаться непосредственно в начале или конце поста и только один раз

- Cсылка размещается в формате: "Страница игры в Steam: URL"