Главная » Документация » Практическое руководство по AI

RSS

Практическое руководство по AI

Приемущества группирования

  1. Информация о перемещениях юнитов хранится в общем списке. Плюс здесь состоит в том, что не нужно каждый раз, когда меняются пункты назначения и цели, копировать одни и те же данные каждому юниту. Все они получают ее из одного общего источника – источника группы.
  2. Взаимодействие нескольких боевых единиц в таких вещах, как постройка сооружения. При этом юниты сразу же занимают определенное место на карте, а не перебирают всевозможные позиции по отношению к другим юнитам, путаясь до тех пор, пока не найдут подходящее положение.
  3. Группы могут быть таким образом организованы, что отдача приказов между юнитами будет занимать столько же времени и данных, сколько отдача приказа отдельному юниту. Очень важно, чтобы данными можно было легко обмениваться. Пересылать информацию между 25 юнитами (или более того) от каждого к каждому – довольно рутинная работа, если не иметь то, что объединяет их всех.
  4. В зависимости от того, как группа сформирована, алгоритм обхода и обнаружения препядствий можно упростить и уменьшить время нахождения пути в лабиринте. Иначе это может стать серьезной проблемой при работе с большим количеством юнитов.

Большое хранилище

Идея – создать место некоторого центрального хранилища данных, без труда используемое юнитами для быстрого обмена данными. Идея – не дублировать информацию, которая будет распологаться в одном единственном источнике организованным так логично, чтобы все последующие дополнения, если они появятся, не вызвали дополнительных ошибок.

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

Это значит, что юниты сами по себе не обладают информацией о том, куда идут, что делают, как происходит анимация, где они находятся. Юнит ВСЕГДА должен быть в группе, до тех пор, пока он передвигается и что-то делает. Если юнит один, он должен принадлежать к группе из одного.

Один из многих

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type
 
TGroupUnit = packed Record
  unitNum: integer; // Номер персонажа
  unit: pUnit; // Данные персонажа
  waypoint: array [0..Pred(50)] of TPoint; // Путь в лабиринте состоящий из точек-координат для юнитов
  action: array [0..Pred(50)] of integer; // Действия, вызываемые точками-координатами
  stepX: integer; // Шаги для отдельных юнитов в режиме
  stepY: integer;
  run: integer; // Действия
  walk: integer;
  sneak: integer;
  fire: integer;
  hurt: integer;
  sprint: integer;
  crawl: integer;
  target: integer; // Цели для юнитов
  targetPos: TPoint; // Позиция цели
end;

Пояснения:

unitNum – номер юнита в группе. Если максимальное число юнитов в группе равно 10, тогда 10 мест в группе доступно. Первый юнит будет с номером 0, и так далее до 8.

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

waypoint – массив. Он содержит все области, на которые юниту прийдется передвинуться в порядке очереди. Все действия и точки-координаты (waypoints) определены только в структуре GroupUnit, если группа не самостоятельное образование, и юнитам нужно передвигаться самостоятельно.

Массив action содержит список действий, привязаных к движениям по точкам-координатам, это цепочка команд. Юниты могут, к примеру, красться по одной территории, затем бежать по другой. Действия игрока становятся более стратегическими и продуманными.

stepX, stepY – это переменные, характеризующие простую скорость объекта. С каждым кадром юнит передвигается по карте в любом направлении. Использоваться это может только с простыми системами, часто уменьшая время вычисления.

Переменныеrun, walk, sneak…отвечают за различные состояния, в которых находится юнит. Это не анимация, а состояния поведения, которые могут переключаться легко или даже работать вместе.

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

Разум толпы

Программа-максимум здесь – создание такой структуры, которая содержит необходимый объем информации для минимизации процедур обработки и поиска. Рассмотрим простую струтуру данный, которая это осуществляет.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
type
 
TGroup = packed Record
  numUnits: integer; // Юниты в группах
  unit: array [0..Pred(4)] of TGroupUnit; // Информация о юните
  formation: integer; // Тип расстановки юнитов в группе
  destPos: TPoint; // Цель
  destPX: integer; // Экранные координаты цели
  destPY: integer;
  wayX: array [0..Pred(50)] of TPoint; // Путь в точках-координатах для группы
  formStepX: double; // Значения используютя для движения шеренги
  formStepY: double;
  formed: boolean; // Если значение true, юниты ведут себя в группе отдельно, иначе двигаются по шеренге
  action: integer; // Планы и действия группы
  plan: integer;
  run: integer;
  walk: integer;
  sneak: integer;
  sprint: integer;
  crawl: integer;
  sniper: integer;
  spotPos: TPoint; // Координаты снайпера
  strategyMode: integer; // Режим стратегии группы
  orders: array [0..Pred(5)] of integer; // Приказы для группы
  goals: array [0..Pred(5)] of integer; // Цели группы
  leader: integer; // Лидер группы
  sentry: TSentryInfo; // Список защиты
  aiState: TAIState; // Состояние AI
end;

Переменная numUnits определяет количество юнитов в группе, а массив unit хранит информацию о группе. Для данной группы максимальное количество юнитов жестко запрограммировано и равно 4..

Флажок formation определяет построение юнитов в группе. Они могут быть построенны в шеренгу и т.п. если изменить значение этой переменной. При этом юниты изменяют свое положение соответствующим образом.

destPos , а также destPX,destPY определяют окончательную цель для группы и быстро посылают эти данные игроку. Каждый юнит идет по своему маршруту. Однако если юниты объединены и идут друг за другом с одинаковой скоростью, нет необходиомости обрабатывать скорость каждого отдельного юнита, когда это можно сделать для всей группы.

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

Действия группы и отдельных юнитов совпадают. Вы заметите, что есть переменная для юнита-снайпера, но она не хранится в структуре GroupUnit, поскольку нет смысла иметь одного снайпера в группе, в то время как остальные юниты отдыхают. Логично выделить этого юнита в свою собственную группу, а затем контролировать его работу на этом уровне. Это пример того, как нужно планировать и разбивать информацию в структуры данных для их наилучшей обработки.

Переменная strategyMode определяет то, как юниты реагируют на врагов. Боевые единицы могут просто нападать, или нападать после каких-то действий со стороны; защищаться; а может просто носиться. Такая простая переменная, с помощью которой можно управлять основными реакциями юнитов, хорошо подходит для того, чтобы выделить отдельные юниты или группы для разного рода ответных действий на ситуации. Кроме того, игрок может устанавливать различные группы в различные режимы так, что они будут знать, что делать, если на них нападет враг.

Массивы orders(приказы) и goals(цели) описываются в специальной базе данных. Когда приказы отдаются, они переопределяются составным группам и каждая из них получает одну и ту же информацию.

По названиям переменных sentry(защита) and aiState (состояние интеллекта) понятно, что они содержат информацию о защите и более подробные данные о структуре и модели интеллекта.

Собираем все воедино

Итак, у нас есть несколько структур для наших групп. Что же делать дальше? Сейчас надо решить, как использовать эти данные в алгоритмах в своей игре.

Решающий момент: внимательно и аккуратно разрабатывайте алгоритмы искусственного интеллекта, чтобы они были гибкими и состояли из нескольких модулей. Это облегчит их последующую доработку,да и вам будет проще обрабатывать отдельные их части. Как и в организации структур данных, каждая функция должна работать независимо и индивидуально. Позже, если вам потребуется, вы сможете запустить этот протестированный алгоритм целиком, в котором понятен каждый отдельный кусок по работе с данными. Если появятся проблемы с вашем AI и вам будет нужно выполнить отладку, вам не прийдется просматривать весь код в поисках ошибки, поскольку будет только один небольшой участок, оперирующий именно с этим типом данных, или, в конечном счете, что-то подобное.

Заключение

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

Главное – добиться лучших результатов, даже без модных кодов. Если это работает – берите это. Девиз, которым пользовались и всегда будут пользоваться разрабодчики игр: «Если это похоже на истину, это истина». Не позволяйте другим людям, которые создают эмуляторы реальных физических систем пудрить вам мозги, когда они говорят, что это плохо каждый кадр прибавлять x к сущестующей координате. Если в вашей конкретной ситуации это работает, творите это. Иногда точные физические процессы используются в некоторых играх, но не во всех. Существует огромное количество способов достичь почти того же самого, но по-другому.

Вы никогда не построите копию существующей реальности. Это факт. Поэтому создайте свой собственный мир.

Страницы : 1 2 3 4 5