Создание ARPG в одиночку. Часть 2 Искусственный Интеллект

Лирика

Одна из основных деталей во всех играх с экшеном - искусственный интеллект (в дальнейшем просто ИИ). Его поведение может как задавать атмосферу, так и поведение игрока. Поэтому буквально сразу после того как "научил" персонажа ходить и пользоваться инвентарём, я принялся за написание ИИ.

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

Тупой, но не слишком....

Создание ARPG в одиночку. Часть 2 Искусственный Интеллект

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

  • Простота. Игрок должен быстро понимать поведение моба, при этом стайки мобов должны синергировать
  • Оптимизация. Врагов много, а компы мощные не у всех, поэтому в коде не должно быть ничего лишнего
  • Быстрая настройка. Каждый из нас любит различные вариации врагов, и было бы не плохо быстро их создавать
  • Взаимодействие с миром. Отличные от игрока механики урона, брони и скилов у мобов будут мешать погружению в процесс

Построение начального алгоритма

Я рассказывал про него в одном из своих видео, но постараюсь так же кратко рассказать всё при помощи печатного текста

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

  • Статы - фиксируют количество здоровья и эффекты на мобе
  • Регистратор - проверяет видит/слышит ли моб игрока
  • Поведение - оно говорит что делать если игрок был замечен, по какой тактике его бить(или убегать)
  • Движение - принимает позицию в которую надо двигаться, и, собственно, управляет скоростью
  • Атака - решает когда надо атаковать, так же задаёт свойства атаки
  • Диалог (о нём поподробнее чуть позже) - решает что и как сказать игроку
  • Анимация - принимает решение какую анимацию воспроизводить исходя из остальных модулей
  • Звук - чтобы моб мог топать при ходьбе и кричать при атаке
  • Смерть - не все мобы просто валяться замертво, у некоторых есть эффекты при смерти (банальный взрыв или разделение на несколько частей), поэтому вывожу её в отдельный класс
Создание ARPG в одиночку. Часть 2 Искусственный Интеллект

Про код чуть-чуть подробнее

Сразу же выделю интерфейс взаимодействия. Важнейшее связующее между блоками

public interface IAi { void Detected(bool value); //Даёт понять виден игрок или нет void Agression(bool value); // Атаковать игрока? void ActionDelay(bool value); //Если играет анимация атаки или урона, модули приостановят работу }

Далее обращусь к регистратору, оговорка на то что он начинает отслеживать игрока только при его приближении (входе в триггер моба)

private void OnTriggerEnter(Collider other) { if(other.tag == "Player") { Stats.playerStats.AddEnemy(stats); playerOnTrigger = true; } } private void OnTriggerExit(Collider other) { if(other.tag == "Player") { Stats.playerStats.RemoveEnemy(stats); playerOnTrigger = false; Ai.DetectedSwitch(gameObject, false); } }

И если игрок в триггере ИИ, то идёт проверка на "слышит" или "видит" моб персонажа.

if(!detected && !actionDelay) { if (curAgressionTimer > 0) curAgressionTimer -= Time.deltaTime; else if(aggression) Ai.AgressionSwitch(gameObject, false); if (playerOnTrigger) { if (CheckHear() || CheckWatch()) { Ai.DetectedSwitch(gameObject, true); } } }

В основном в модулях нечего особо интересного нет, поэтому пожалуй остановимся на поведении

В нём используется несколько вариантов агрессии от пассивной, до мордобоя, и несколько видов тактик:

public enum typeAgression {Low = 0, Normal = 1, High = 2 } public typeAgression aggressionMode; public enum typeTactic { Simple = 0, Back = 1, Bite = 2, Run = 3 } public typeTactic tacticMode; Dictionary<typeTactic, Tactic> tactics = new Dictionary<typeTactic, Tactic> { [typeTactic.Simple] = SimpleAttack, [typeTactic.Back] = BackAttack, [typeTactic.Bite] = BiteAttack, [typeTactic.Run] = Run };
  • Simple - просто бежит на игрока с шашкой наголо
  • Back - примерно тоже самое что и Simple, но пытается зайти сбоку или сзади
  • Bite - когда персонаж отвернулся то ИИ нападает, а когда разворачивается убегает
  • Run - просто убегает от игрока

Методы получились очень маленькие, даже я не ожидал такого...

static void SimpleAttack(AiMove aiMove) => aiMove.SetTarget(Stats.playerStats.Position()); static void BackAttack(AiMove aiMove) => aiMove.SetTarget(Stats.playerStats.LocalBackward(2)); static void BiteAttack(AiMove aiMove) { if (Vector3.Angle(Stats.playerStats.Position() - aiMove.Position, Stats.playerStats.Forward()) <= 60) SimpleAttack(aiMove); else Run(aiMove); } static void Run(AiMove aiMove) { aiMove.SetTarget(Stats.playerStats.LocalForward(5)); }

На этом всё самое интересное кончается :с
Если хочется побольше узнать то я успел записать видео-разбор:

Итог

На данный момент всё смотреться сыровато. Но тем не менее фундамент заложен, и я думаю что он не плох.

Проведя пару тестов я понял, что добился того чего хотел, ИИ ведёт себя просто и понятно, а в больших количествах начинает играть новыми красками. То что надо для моей игры :)

Создание ARPG в одиночку. Часть 2 Искусственный Интеллект

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

1919
6 комментариев

Q-обучение или генеративное обучение собираешься использовать?

Ответить

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

1
Ответить

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

Ответить

Спасибо за то что подметил, я сам только сейчас увидел свой косяк

Ответить