ADVENTURE PROJECT
Игра - дело серьезное, а игра адвентюрная - дело серьезное вдвойне. Если Вы полагали, что дав серию статей по методике работы с адвентюрными игровыми программами, мы с ними закончили, то Вы чуть-чуть ошибаетесь.
Сегодня мы начнем новый цикл статей и покажем на примере адвентюрных программ как могут применяться принципы искусственного интеллекта. А это уже согласитесь дело совсем нешуточное и, возможно, знание этих элементарных базовых принципов поможет когда-нибудь в будущем в Вашей практической работе.
Первые адвентюрные игры в основной представляют собой просто путешествие по игровым полям (локациям), информация о которых содержится в памяти ЭВМ. Но с течением времени программы стали усложняться, и в первую очередь усложнение пошло как по пути введения в игру элементарной графики, так и по пути введения некоторых базовых концепций, связанных с искусственным интеллектом. Первыми образцами такого подхода стали The Hobbit и Sherlock фирмы MELBOURNE HOUSE и в какой-то степени Valhalla фирмы LEGEND.
Такой подход позволил дать игровым персонажам возможность вести в общем программном окружении как бы собственную жизнь. В программах появился эффект "реального времени". И Ваш главный герой, которым Вы управляете, получает возможность общаться с другими персонажами и "жить" в игровом пространстве.
И, как Вы увидите, делается это совсем несложно. Все, что для этого надо - это определить правила поведения героев и правила их реакции на игровые ситуации, возможные в ходе игры.
Вы, должно быть, знаете, что когда дело доходит до обработки правил, то очень хорошо подходит язык ПРОЛОГ, который кстати для "Спектрума" тоже реализован в версии "ZX-Микропролог", но мы в рамках данной статьи будем обсуждать базовые концепции на примерах, написанных на БЕЙСИКЕ.
Конечно, БЕЙСИК далеко не идеален, но зато понятен всем, а уж применять основные принципы Вы можете где хотите и на том языке, какой Вам будет удобнее - ПАСКАЛЬ, СИ и др.
Мы не будем останавливаться на методике разработки сценария игры - это важный момент, но не тема данной статьи. Для этого Вам необходимы фантазия, вдохновение, художественный вкус. Скажем только, что как правило ситуации реальной жизни имеют более мощный эффект, чем надуманные конструкции.
Когда сценарий игры продуман, на бумаге расписывается карта локаций, по которым могут путешествовать персонажи.
Программа может иметь несколько игровых пространств, перемещение между которыми выполняется подъемом по лестницам, спуском в ущелья и т.п. В таком случае локации помечаются сначала меткой, указывающей на уровень, а затем на координаты позиции. Эти метки локаций могут не иметь никакого отношения к тому, с какими описаниями они появятся в игре, но служат как бы путеводителем программисту и дизайнеру программы, особенно если это разные люди.
Предположим, что в одном академическом НИИ, расположенном на морском берегу, группа налетчиков похитила уникальный опытный экземпляр часов, способных управлять развитием Вселенной. Преступники скрылись на моторной яхте, а часы перепрограммировали на обратный ход. Время пошло вспять.
Вас зовут Инф. Вам, с Вашими помощниками Орой и Комом, надо найти налетчиков и вернуть часы до того, как обратный ход времени превратит Вас в ребенка или вообще уничтожит Вас как еще не появившегося на свет.
Игра начинается на берегу моря. Двигаясь вправо, Вы попадаете в моторную лодку. Остальные направления показаны на рис.1.
0/3 море +
лодка
0/8 берег
Рис.1
На этом этапе Вам для описания локации достаточно одного-двух слов, но Вы-то конечно помните, что в игре каждая локация будет появляться со своим каким-то достаточно подробным описанием.
Лучше всего завести отдельную картотеку. Пометьте каждую карточку шифром, определяющий номер локации. Затем дайте краткое описание, полное описание и список объектов (предметов), которые могут быть здесь обнаружены.
Карточка может выглядеть примерно так, как показано на рис.2.
0/2 МОРЕ
Вы упали в ледяную воду. От холода у Вас начинают неметь конечности. Еще немного, и вы утонете.
+ ЛОДКА
Вы взобрались на борт моторной лодки, слегка покачивающейся на волнах.
ПРЕДМЕТЫ:
- ключ зажигания;
Рис. 2
В качестве уровня игрового пространства здесь взят 0. Всякий уровень, находящийся выше, будет обозначаться положительным числом, а уровень ниже - отрицательным. Например, когда Вы настигнете налетчиков и подниметесь на борт яхты, уровень будет +1, а когда спуститесь в трюмное помещение, то -1.
Когда Вы перейдете от разработки проекта непосредственно к программированию, то обнаружите, что локации и объекты могут конкурировать друг с другом и сделать программирование более сложным, чем ему положено быть. Например, лодка может поставить Вас перед проблемой, которая хоть и не очевидна, но оказывает влияние на структуру программы и ход игры. Проблема в том, чем считать лодку - локацией или объектом, поскольку она перемещается.
Если ее считать объектом, то можно ею не заниматься до тех пор, пока не дойдете до размещения объектов. Описание локации в этом случае такое, как на рис.2.
Учет лодки как объекта, имеет определенные преимущества, поскольку тогда ее можно перемещать по ходу игры. Более того, с ней могут перемещаться и персонажи. С точки зрения гибкости игры гораздо удобнее иметь лодку и перемещаться с нею по локациям, чем описывать путь по фиксированным локациям пространства игры. При таком подходе единственная структура данных, необходимая нам пока - это обычный массив.
На рис.3 показан текст программы, описывающей приведенную выше карту в виде двумерного массива размером 3х3. Каждый элемент массива имеет место для 10 символов для краткого описания локации.
10 DIM g$(3,3,10) |
|
20 FOR i=1 TO 3 |
|
30 FOR j=1 TO 3 |
|
40 READ g$(i,j) |
|
50 NEXT j: NEXT i |
|
60 DATA "Mope","Mope", |
"Море" |
70 DATA "Море","Берег" |
,"Море" |
80 DATA "Море","Берег" |
,"Море" |
90 REM PRINT ROUTINE |
|
100 FOR i=1 TO 3 |
|
110 FOR j=1 TO 3 |
|
120 PRINT g$(i,j);" "; |
|
130 NEXT j |
|
140 PRINT |
|
150 NEXT i |
|
Рис.3
Если Вы пишете программу в машинном коде, Вы сведете все данные в единую таблицу, а на конкретный элемент будете указывать с помощью индекса (смещения).
Конечно, Вы понимаете, что приведенный выше пример расточительно использует ограниченную память компьютера. Так, семь раз повторяется локация с описанием "море" и два раза "берег". Вы, конечно, найдете способы сэкономить здесь немалый объем. Надо также иметь в виду и ограничения по скорости, если работаете на БЕЙСИКе. "Спектрум" может затратить пол-минуты на то, чтобы обработать массив всего лишь 100х100.
Теперь перейдем к проектированию персонажей. Этот процесс состоит из трех основных этапов:
- характеристика;
- изменчивость;
- коммуникабельность.
Последние два взаимосвязаны. Действительно, взаимодействие между персонажами по ходу игры неминуемо приводит к изменению их действий. Любые взаимодействия отражаются на атрибутах, присвоенных персонажам, а те в свою очередь приводят к изменениям во взглядах на внешний мир и, соответственно к изменению поведения по отношению к другим персонажам.
Действия и перемещения одного персонажа вызывают перемещения других персонажей (и объектов!) в игровом пространстве. Например, в зависимости от смелости одного персонажа он может взять или не взять какой-либо объект на борту вражеской яхты (пищу или, скажем оружие), а это действие может заставить страдать другой персонаж в определенное время (от голода или от безоружности). По этой причине фактор изменчивости является важнейшим при проектировании игры с элементами ИИ (искусственного интеллекта).
Первый этап - задание характеристик персонажам понятен. Его сложность зависит от того, насколько сложной Вы планируете сделать программу. Уже давно в играх сложилась определенная система атрибутов, которая включает в себя:
- силу;
- интеллект;
- ловкость;
- пси-энергию;
- стойкость.
Если с первыми тремя все понятно, то пси-энергия характеризует магические способности героя, а стойкость - способность выдержать определенное количество ударов, не будучи травмированным.
Вы видите, что такая система атрибутов нацелена на игры, в которых сражение - это естественное состояние героев, для чего собственно и идет игра.
Эта система не годится для более интеллектуальной программы с более сложным поведением персонажей, поскольку никаких качеств характера героя она не описывает, а потому не сможет определять его самопроизвольное поведение в игровой среде, что необходимо для программы с искусственным интеллектом.
Желательно, чтобы в программе герои могли бы испытывать чувства, например, такие, как боль, страх, ненависть и другие, неотъемлемо присущие человеку.
Вернемся к нашему проекту программы. Предположим, пока Ком остается в лодке, Вы с Орой ныряете в пучину моря, где во мраке видите очертания затонувшей яхты и силуэты двух чудовищ, охраняющих ее - Крама и Брога. Они сильны, но малоподвижны. В то же время, у них очень неплохо с интеллектом. Настолько неплохо, что они не будут ввязываться в драку или продолжать ее, если у них нет стопроцентной уверенности закончить ее без особого ущерба для себя. Атрибуты, которыми может быть в дальнейшем описано поведение всех персонажей, могут быть такими, как показано на рис.4.
Атрибут |
Изменчивость |
Диапазон изменения +10/-10 |
Эмоции |
x |
стабильные / нестабильные |
Энергия |
x |
энергичный / вялый |
Сила |
x |
большая / малая |
Интеллект |
|
гений / тупица |
Совесть |
x |
большая / отсутствует |
Образованность |
|
высокая / низкая |
Рис. 4
Отмеченные знаком "x" атрибуты могут меняться по ходу игры. Диапазон изменения от "-10" до "+10". Так, например, если Ваша энергичность имеет атрибут "-5", то в очередной ситуации, в которой она будет учитываться, она зачтется не в Вашу пользу. Если по ходу программы Вы будете делать ошибки, то атрибуты эмоций, силы и совести также будут изменяться.
Ключ к использованию этих атрибутов в системе искусственного интеллекта состоит в том, как они взаимосвязаны, как влияют один на другой и как влияют на поведение персонажей. Нет больше однозначно хороших или однозначно плохих героев. Теперь Вы можете покорять врагов, а можете даже делать из них друзей.
Конечно, по ходу игры эти атрибуты могут изменяться сотни раз, но в начале игры они должны быть заданы, например, так, как показано на рис.5.
Атрибут |
Инф |
Ора |
Крам |
Брог |
Эмоции |
5 |
-2 |
-3 |
2 |
Энергия |
4 |
-1 |
6 |
-3 |
Сила |
3 |
2 |
4 |
4 |
Интеллект |
7 |
2 |
4 |
4 |
Совесть |
6 |
5 |
-4 |
-3 |
Образованность |
6 |
6 |
1 |
2 |
Рис. 5
Определив систему атрибутов, Вы теперь можете выработать критерии поведения своих персонажей, образовав комплексные атрибуты, см. рис.6.
Характеристика персонажа |
От чего зависит |
Гнев
Мужество Трусость Счастье Настроение |
Энергия, Интеллект, Сила Энергия, Сила, Совесть Энергия, Сила, Совесть Интеллект, Эмоции, Энергия Эмоции, Энергия, Совесть |
Рис. 6
Мы позже займемся выведением формул для расчета характеристик персонажей через их атрибуты, но сейчас имейте в виду, что все здесь зависит от Вас. Вы сами можете задать эти формулы. Например:
мужество = энергия + сила + совесть
или скажем:
мужество = 2*энергия + 5*сила + 3*совесть.
Вы же можете вычислить и другие какие-либо характеристики, не указанные выше, например, способность к самопожертвованию.
Скоро Вы увидите, что зная атрибуты персонажей, Вы сможете на глаз предсказать их поведение в той или иной ситуации, а также что произойдет, если например Инф совершит какое-то действие.
Благодаря такому подходу, персонажи могут приобрести некоторую автономию. Они смогут сами "решать", что им делать в той или иной ситуации, а не быть марионетками в руках играющего. Такая игра становится намного интереснее, неожиданнее, да и вообще меняется сама ее природа.
После того, как данные по персонажам определены в исходной таблице (рис.5), можно приступить к программированию. Предельно простой сценарий показан на рис.7.
100 |
LET c$="":LET p$="":LET n$="" |
|
|
110 |
REM заполняем банк атрибутов |
|
|
120 |
DIM a(4,6):REM - 4 персонажа, 6 атрибутов |
|
130 |
RESTORE 190 |
|
|
140 |
FOR i=1 TO 4 |
|
|
150 |
FOR j=1 TO 6 |
|
|
160 |
READ a(i,j) |
|
|
170 |
NEXT j |
|
|
180 |
NEXT i |
|
|
190 |
DATA 5,4,3,7,6,6: REM - Инф |
|
|
200 |
DATA -2,-1,2,2,5,-6: REM -Opa |
|
|
210 |
DATA -3,6,4,4,-4,1: REM - Крам |
|
|
220 |
DATA 2,-3,4,4,-3,2: REM - Брог |
|
|
230 |
REM - начало экспериментального сценария |
|
240 |
CLS |
|
|
250 |
PRINT "Мрачные очертания проступают" |
|
260 |
PRINT "перед Инфом и Орой." |
|
|
270 |
PRINT "Они видят корпус яхты, на' |
|
|
260 |
PRINT "которую указал локатор." |
|
|
300 |
REM - ввод противников |
|
|
310 |
IF a(3,2) OR a(3,3) OR a(3,5)<-1 |
THEN LET c$= |
'Брог": |
|
LET f$="одно чудовище охраняет |
|
|
|
GO TO 340 |
|
|
320 |
IF a(4,2) OR a(4,3) OR a(4,5)<-1 |
THEN LET c$= |
'Крам": |
|
LET f$="одно чудовище охраняет |
|
|
|
GO TO 340 |
|
|
330 |
IF c$="" THEN PRINT "яхта появляется перед Вами": |
|
PRINT "дверь в рубку открыта": |
|
|
|
|
GO TO 380 |
|
|
|
340 |
REM |
|
|
|
350 |
PRINT "Корпус яхты прорисовывается |
|
|
|
360 |
PRINT "в темноте" |
|
|
|
370 |
PRINT 1$;"дверь в рубку.": GO TO 400 |
|
|
|
380 |
PRINT "Вы проходите в помещения" |
|
|
|
390 |
STOP |
|
|
|
400 |
REM - решение стоит ли сражаться |
|
|
|
410 |
IF a(1,2) AND a(1,3) AND a(1,5)<-8 LET п$="Инф": GO TO 440 |
THEN |
LET p$= |
'Opa": |
420 |
IF a(2,2) AND a(2,3) AND a(2,5)<-8 |
THEN let p$= |
'Инф": |
|
LET п$="Ора": |
|
|
|
|
GO TO 440 |
|
|
|
430 |
LET р$="Инф и Ора": STOP |
|
|
|
440 |
REM - один из них уплывает |
|
|
|
450 |
PRINT п$; "Холодеет при мысли о схватке |
и" |
|
460 |
PRINT "уплывает к лодке." |
|
|
|
470 |
PRINT р$; "остается с чудовищем" |
|
|
|
480 |
PRINT "один на один": STOP |
|
|
|
Рис. 7
Вам должно быть понятно из этого примера как учитывается влияние атрибутов на поведение персонажей. Возьмем чудовищ.
Строка 310. Если у Крама не все в порядке с силой или с энергией или с совестью, он не выползает на поле битвы.
То же самое делает и Брог в строке 320.
Если ни тот, ни другой не охраняют вход, то через строку 330 Вы с Орой проникаете на
яхту.
Аналогично и с положительными героями. Их поведение рассматривается в строках
400.
Есть только одна особенность. Чудовища анализируются оператором OR, а ваши герои оператором AND. Это сделано специально, чтобы у первых было больше оснований не вступать с Вами в схватку, ведь если ИЛИ энергии, ИЛИ силы, ИЛИ совести у них мало, они уйдут.
Для вас же наоборот, надо, чтобы ОДНОВРЕМЕННО И того, И другого И третьего не хватало, чтобы бросить товарища в беде. Конечно, это менее вероятно и возможно лишь в совсем отчаянном положении, когда действительно сражаться бесполезно, а надо думать о конечной задаче.
Вам должно быть ясно, что приведенный пример страшно расточителен по расходу памяти и предельно примитивен. Конечно, на БЕЙСИКе реально такие вещи не пишут. Но как иллюстрация концепции он годится и должен быть понятен. Степень сложности, которую Вы определите для себя - дело Ваше. Вы можете анализировать сотни факторов, составлять любые уравнения для расчета критериев - это ваше право.
И напоследок обратим здесь еще внимание на один аспект взаимосвязи. Предположим, что у Брога был кинжал. Что тогда, если он не вышел на битву? Вам стало легче от того, что Вы не пострадали, но зато Вы лишились возможности завладеть кинжалом и впоследствии его использовать. Вы даже никогда и не узнаете, чего лишились - вот что самое интересное. Это тот случай, когда программа начинает жить собственной жизнью, независимо от Вас.
(Продолжение в следующем выпуске)