Пишем ИИ для игры. Часть 1: Как найти противников в поле зрения
Всем привет. С сегодняшнего дня я решил начать написание цикла статей по работе с ИИ противника. В ходе данного цикла я хочу показать на простых примерах, как можно сделать ИИ в игре, который будет учитывать поле зрения противника, уровень издаваемого шума, умеет патрулировать местность, ставить приоритетные цели и обладать различными типами поведения.
В конце цикла статей наш ИИ будет уметь:
- Получать список целей по FOV;
- Искать путь до ближайшей цели, будь то враг или что-то другое;
- Обладать типом (враг, союзник, болванка);
- Обладать поведением (патруль, поиск цели, бой, следование, убегание);
- Учитывать уровень шума и освещенности;
- Работать с инверсной кинематикой (получать Impact конечностей, смотреть на врагов);
Для чего это нужно?
В сегодняшней статье я расскажу о простой реализации поля зрения противника. Дабы исключить архитектурные особенности - мы сделаем все на обычных монобехах.
Итак, начнем с того, что должно делать наше поле зрения:
- Находить цели, которые попадают в угол обзора;
- Ставить приоритет на ближайшую цель в области обзора;
- При выходе текущей цели из поля обзора - сохранять её до определенной дистанции;
- При полной потере цели - переключиться на другие;
Интерфейс Field of View
Начнем с того, что нам нужен некий интерфейс, который сможет просто обрабатывать наше поле зрения:
Рассмотрим, что содержит наш интерфейс:
- Параметры Radius, Angle - для того, чтобы получить возможность узнать информацию о FOV;
- Параметр CurrentTarget (в моем случае для простоты используется Transform, но лучше сделать интерфейс ITarget и работать с ним);
- Методы для проверки целей - HasTargets, GetAllTargets, GetNearestTarget и ForceRecalculate.
Почему здесь нет метода поиска целей, а сделан только ForceRecalculate? Мы делаем просчет внутри самого компонента FOV, а все его данные получаем через его методы обработки целей. ForceRecalculate нужен нам только тогда, когда к примеру текущая цель умерла и хочет оповестить наш объект об этом.
Базовая реализация FOV
Теперь приступим к самой реализации FOV. По своей сути он работает через оверлап коллайдера, однако вы можете использовать Raycast. Также у компонента FOV есть таймер пересчета целей и чем меньше он будет, тем больше будет нагрузки и тем выше точность поиска. Таймер полезен тогда, когда игрок непосредственно видит ИИ противника и для него выставляется наименьший таймер, а для противников в далеке - наибольший.
Теперь разберем подробнее составляющие кода:
- В методе Start() мы запускаем наш счетчик проверки FieldOfView через интервал. В моем случае используется UniRx, но вы можете сделать реализацию таймера по-другому.
- Метод FieldOfViewCheck() запускает процесс проверки целей внутри поля зрения. Если изначально у нас нет никаких целей - мы проверяем есть ли кто-то по нужному слою в физике, затем смотрим ближайшую цель и добавляем её в список. Если же цель есть - мы смотрим дистанцию до неё вне зависимости от поля зрения и если главная цель слишком далеко - пересчитываем снова список целей.
- Дополнительные методы GetAllTargets, GetNearestTarget, HasTargets и ForceRecalculate служат вспомогательными. Они могут использоваться в нашем контроллере ИИ.
Теперь мы научили нашего противника определять ближайшую цель в поле зрения:
Так же важно, что если цель покинет поле зрения, то герой останется на ней сфокусирован, пока её дистанция не увеличиться больше допустимой, в этом случае он опять будет переключаться на ближайшую цель в поле зрения. Так же нужно учесть, что пока здесь не реализовано поведение, которое учитывает урон от ближайших целей (о чем мы поговорим в следующих частях цикла).
Итог
Проверка поля зрения позволяет нам убедиться, что наш ИИ вообще видит кого-то перед собой, цель не перекрывается и задать приоритет по целям исходя из дистанции. В дальнейшем, мы будем комбинировать FieldOfView с показателями шума, издаваемого целями, а также задавать поведение для нашего ИИ.
Следующая часть статьи будет включать в себя обработку целей в зависимости от паттерна поведения нашего ИИ, а также же учитывать инверсную кинематику для того, чтобы наш герой поворачивал голову и туловище к ближайшей цели.
Буду рад пообщаться на эту тему и послушать о ваших реализациях FOV.