Gamedev LectureСтатьи

Лекция #12. AI. Подходы, тимплей, взаимодействие с миром, оптимизации для большого мира. [Лектор - roman_p]

Автор:

Disclaimer: некоторые опечатки поправлены, некоторые реплики передвинуты. полный лог

[22:06] <roman_p> 1. Подходы.
[22:06] <roman_p> Какие есть методы построение AI.
[22:07] <roman_p> Предположим есть у нас class NPC - мы им и будет в дальшейшем управлять.
[22:07] <roman_p> a) самый простой метод. делаем в NPC - virtual function DoWork (delta_time);
[22:08] <roman_p> и для каждого NPC - пишем свой код. hard coded.
[22:08] <roman_p> если игра маленькая и NPC мало - самое то.
[22:09] <roman_p> усложняем задачу.
[22:09] <roman_p> вводим понятие - мозг. brain. например - у убийцы один brain, у полицейского другой, у дельфина - третьий.
[22:10] <roman_p> тут просят привести пример virtual function DoWork (delta_time).
[22:12] <roman_p> void NPC::DoWork (Time dt)
[22:12] <roman_p> {
[22:12] <roman_p> if ( pathfinder.IsFinished () ) pathfinder.Go ( RandomPosition () );
[22:12] <roman_p> }
[22:13] <roman_p> самое простое. NPC будет просто шняряться в случайную точку.
[22:15] <roman_p> если персонажей в игре - много - тогда можно заметить что разные NPC - могут выполнять одно и тоже.
[22:16] <roman_p> например: AI дельфина и кита - одинаковое.
[22:16] <roman_p> можно сделать - так:
[22:17] <roman_p> class NPC_Swimming : public NPC;
[22:17] <roman_p> class NPC_Dolphin : public NPC_Swimming;
[22:17] <roman_p> class NPC_Whale : public NPC_Swimming;
[22:18] <roman_p> и описать DoWork только у NPC_Swimming.
[22:18] <roman_p> а можно сделать по другому.
[22:18] <roman_p> AI дельфина и кита - это мозг. Brain. один и тот же brain.
[22:19] <roman_p> class Brain;
[22:19] <roman_p> virtual Brain::DoWork (dt);
[22:19] <roman_p> а в классе NPC - просто хранить указатель на Brain.
[22:21] <roman_p> если и остальные параметры NPC (все, что не относится к AI) - можно сделать переменными - тогда можно сделать один класс NPC на всю игру.
[22:21] <roman_p> без наследования от него.
[22:21] <roman_p> void NPC::DoWork (Time dt) { if (brain) brain->DoWork (dt); }
[22:23] <roman_p> итого:
[22:24] <roman_p> class Brain_Swimming; // мозг водоплавающего
[22:26] <roman_p> можно заметить - если написать несколько классов порожденных от Brain - что есть некоторые куски - которые повторяются.
[22:27] <roman_p> то, что повторяется во всех мозгах - назовем Поведение. Behavior.
[22:28] <roman_p> class Behavior;
[22:28] <roman_p> есть такие типичные поведения:
[22:28] <roman_p> class Behavior_RunAway; // убегать куда глаза глядят
[22:28] <roman_p> class Behavior_Attack; // атаковать
[22:29] <roman_p> class Behavior_HitAndRun; // хитрая атака
[22:29] <roman_p> class Behavior_Hide; // спрятаться
[22:29] <roman_p> и т.д.
[22:30] <roman_p> на первых порах - эти поведения можно тупо помещять внутрь нужного класса Brain.
[22:31] <roman_p> void Brain_Looter::DoWork (Time dt)
[22:31] <roman_p> {
[22:32] <roman_p> if ( SomeoneNearMe (4.5) ) behavior_runaway.DoWork (dt, 20.0);
[22:33] <roman_p> else if ( GetSleeperAround (10.0) ) behavior_attack.DoWork ( dt, GetSlepperAround (10.0) );
[22:33] <roman_p> else behavior_playthefool.DoWork (dt);
[22:33] <roman_p> }
[22:34] <roman_p> мозг Лутера:
[22:34] <roman_p> если есть кто-то рядом на расстоянии 4.5 метра - тогда сматываемся на 20 метров.
[22:34] <roman_p> если кто-то спит рядом (10 метров) - тогда убиваем во сне его.
[22:35] <roman_p> иначе - просто слоняемся по округе.
[22:36] <roman_p> комбинурую разные условия и поведения (behavior) - уже можно писать хоть какое-то AI ;)
[22:36] <roman_p> теперь углубимся в тему этих самих условий.
[22:37] <roman_p> условия - это bool SomeoneNearMe (float dist) и более сложные варианты.
[22:37] <roman_p> введем понятие Perception. Восприятие.
[22:38] <roman_p> Perception: это глаза, уши, память, тепловизор, радар, и т.д.
[22:38] <roman_p> у NPC - есть список Perception *
[22:39] <roman_p> у каждого perception-а может быть набор инициализирующих параметров.
[22:39] <roman_p> например для Perception_Eye - это на какое расстояние он видит. И т.д.
[22:40] <roman_p> для каждого NPC - задаются свой набор perception. через ini-файл или в спец. редакторе.
[22:41] <roman_p> у Perception есть определенный набор виртуальных функций типа: NPC * GetEnemy (), NPC * GetFriend (), etc.
[22:42] <roman_p> потом у самого NPC пишется функция NPC * NPC:GetEnemy () - которая пробегает по всем perception и выбирает самого ближнего врага.
[22:43] <roman_p> Perception_Radar - самое простое. Просто глядим через стенки и ищем ближайшего. Двигало должно быстро находить ближейшего NPC.
[22:44] <roman_p> Perception_Eye - почти радар - только еще трейсит луч, чтобы отсечь невидимых NPC.
[22:44] <roman_p> Perception_Hear - работает в области звуков, работает с Sound Engine и Sound map уровня.
[22:46] <roman_p> самое интересное - это Perception_Memory - он запоминает какие враги где столи раньше.
[22:47] <roman_p> Инициализирующие параметры - сколько врагов можно запомнить и как долго их хранить.
[22:48] <roman_p> есть есть perception memory - тогда AI сможет догонять врагов, какие скрылись.
[22:49] <roman_p> т.е. perception eye - говорит "никого не вижу", perception hear - "никого не слышу", а perception memory - "вот, в таких то координатах N-секунд назад был враг".
[22:49] <roman_p> итого, AI подойдет к углу рядом с которым последний раз видили врага, а потом уже perception_eye его и заметит.
[22:50] <roman_p> ...или не заметит - если он хорошо спрятался - забежав за другой угол ;)
[22:51] <roman_p> кто использует perception-ы? да, кто угодно, кто может вызывать функции NPC.
[22:52] <roman_p> очень плотно использует perception-ы другое понятие. Условия. Condition.
[22:53] <roman_p> условия - можно делать отдельными функциями или классами.
[22:53] <roman_p> например есть условие: NPC * SomeoneNearMe (float dist)
[22:54] <roman_p> это условие - обращяется к perception-ам, ищет сразу и врагов и друзей с учетом расстояние dist.
[22:55] <roman_p> или условие: NPC * GetSlepper (float dist);
[22:55] <roman_p> выбирает всех NPC до каких может дотянуться и смотрит - не спят ли они. например, через bool NPC::IsSleeper () const;
[22:56] <roman_p> <CEMEH> Логика выбора между [01:48] <roman_p> т.е. perception eye - говорит "никого не вижу", perception hear - "никого не слышу", а perception memory - "вот, в таких то координатах N-секунд назад был враг". - внутри GetEnemy или умеет кастомизоваться?
[22:57] <roman_p> я рассказываю все - в обобщенном виде. без деталей.
[22:58] <roman_p> например - можно ввести в Perception - float priority
[22:58] <roman_p> приоритет ощущения.
[22:58] <roman_p> у perception memory - приоритет самый низкий.
[22:58] <roman_p> т.е. мы сначала смотрим на eye (высокий приоритет), а потом уже на head (пониже) и в последнюю очередь на memory.
[22:59] <roman_p> в конечных мознах - приоритеты можно и поменять. например очень забавно будет - если их все переставить местами ;))
[23:00] <roman_p> т.е. перс будет стараться сначала атаковать всех тех, кто пытается спрятатся или убежать.
[23:01] <roman_p> итак:
[23:01] <roman_p> perception - хранятся в NPC. набор уникален для каждого NPC.
[23:02] <roman_p> condition - хранятся в brain. или существуют в виде свободных функций.
[23:02] <roman_p> behavior - хранятся в brain.
[23:02] <roman_p> ссылка на brain - храниться в NPC.
[23:03] <roman_p> все этом может задаваться как: hardcoded, в ini-файлах, или в удобном rad-редакторе ;)
[23:04] <roman_p> первая часть - Подходы кратко освещена. есть вопросы? ;)

[23:05] <_TwilighT_> подходы? :) это один подход %)
[23:07] <roman_p> тут несколько вариантов, от самого простого hardcoded NPC::DoWork до сложной системы взаимодействий кучи классов.

[23:06] <kas> я пропустил наверна, а про то что в скриптах а что хардкодед было?
[23:07] <roman_p> kas, а я разве хоть раз сегодня произнес слово скрипт вообще? ;)
[23:07] <kas> ну, я и уточняю :)
[23:08] <roman_p> значит так. про скрипты. зачем они нужны.
[23:08] <roman_p> а) в скриптах можно хранить информацию, которую можно было бы хранить в ini-файлах.
[23:08] <roman_p> б) для написания brain полностью или частично на скрипте.
[23:09] <dotprod> скрипты нужны для увеличения кастумизабельности
[23:09] <dotprod> так чтобы дезигнер мог менять brain`work на лету
[23:10] <roman_p> dotprod: к сожалению - я таких дизайнеров не видел.
[23:10] <dotprod> не мучая кодера просьбой поскорее дать новый билд
[23:10] <dotprod> но тут есть одна загвоздка
[23:10] <dotprod> далеко не все можно сделать на скриптах
[23:10] <roman_p> в МагииКрови - все было на скриптах.
[23:10] <roman_p> Но пользовались скриптами этими - исключительно программисты.
[23:11] <kas> что включает в себя слово всё?
[23:11] <roman_p> Все: это пункты а) и б)
[23:11] <dotprod> так, а перед написанием скриптов была проведена какя-нить работа по определению набора необходимых ф-ций?
[23:12] <dotprod> тоесть скрипты обращаются к движку через некое "API"
[23:12] <dotprod> которое было создано прогерами
[23:12] <dotprod> так вот вопрос в том, на каком этапе девелопинга все эти ф-ции собирать и выносить в API?
[23:13] <roman_p> dotprod: никакого API наружу не было. Был только набор: perception, condition, behavior.
[23:13] <roman_p> этого достаточно для AI.

Страницы: 1 2 3 4 Следующая »

5 февраля 2006

Комментарии [12]