Текстовый квест своими руками

Posted by Anuriel on июня 30, 2004 - 00:00

…глаза его отвисли, челюсть выкатилась из орбит…
Один хороший текстовый квест

Знаете, какое первое желание студента или школьника, едва овладевшего азами программирования? Нет, не стать Биллом Гейтсом… это приходит позже :-). Написать собственную игру, неважно какую, хоть Тетрис, хоть Quake, ведь главная причина такого желания — приобрести авторитет в собственных глазах. Так вот, прочитав это вступление, угадайте с трех раз, чем мы сегодня будем заниматься? Да, писать собственную игру. Ну, не StarCraft и даже не Unreal, так что в TOP-10 она может и не попасть, но ведь это не есть наша нынешняя цель. Короче, господа хорошие, мы с вами пишем текстовый квест.

Несмотря на общепринятое мнение, что текстовые квесты были первым жанром компьютерных игр, на самом деле все было не так. Первая компьютерная игра — Space War — была написана группой американских студентов в 60-е годы. Это была межзвездная война двух кораблей, между которыми находилась черная дыра. Довольно оригинально на то время, хотя и не очень, учитывая буйное помешательство тогдашнего поколения на научной фантастике.
Если вы считаете, что текстовые квесты — пережиток прошлого, то глубоко заблуждаетесь. Во-первых, они куда интеллектуальнее и интереснее, чем всякие там тетрисы, арканоиды, пасьянсы и Die Hard'ы. Во-вторых, я играл во многие новые текстовые квесты и почти все они мне более или менее понравились. Перед написанием собственной игры советую посетить сайты http://www.text-adventure.narod.ru и http://rusgames.boom.ru и накачать оттуда массу интереснейших вещей.

Предлагаю начать. Итак, сначала о том, что нам потребуется. Нам нужен компилятор языка C++ (рекомендую Borland С++ версии 2-3.1) и азы языка С++ (многого от вас не потребуется, все то, что нужно, можно найти в популярных изданиях). Будем считать, что все это имеется в наличии, и приступим к написанию собственной игры.
Сначала — главная концепция. Игра построена на общении пользователя с машиной — он вводит команду (например, "взять топор"), а компьютер анализирует введенную строку, находит в ней команду ("взять") и предмет действия ("топор"). Затем на экран выводится сообщение, адекватное введенной команде (например, "я подобрал топор" или "он мне не нужен"). Многие текстовые квесты не запрограммированы на распознавание конкретной фразы, они ищут ее элементы во введенной команде. Иначе говоря, алгоритм выглядит не так:

if(user_command=="взять топор") printf("Мне не нужен топор");

а так:

if(find("взять")==1&&find("топор")= =1) printf("Мне не нужен топор");

Здесь find(char *what_to) — это условная, несуществующая (пока) функция, которая выполняет поиск слова what_to во введенной пользователем строке и возвращает значение 1 при удаче. Преимущество этого алгоритма в том, что пользователь может ввести и "взять топор", и "я думаю, надо бы взять этот топор", и программа в обоих случаях даст положительный результат.
Еще один распространенный алгоритм заключается в анлализе только первых трех-четырех букв, что позволяет отсекать окончания слов.
Сейчас мы опишем искомую функцию find, выполняющую оба алгоритма, и функцию input_(), которая позволяет производить ввод команды (а-ля scanf() или cin>>, только вводимое слово не прерывается на пробеле). Итак:

#include<stdio.h>
#include<conio.h>
void input_(void);
int find(char *what_to); /*Прототипы наших функций*/
int x, xy; /*Вспомогательные переменные*/
char user_command[100]; /*Переменная команды, вводимой пользователем*/

void main(void)
{
/*Здесь у нас код самой игры */
}
int find(char what_to[4]) /*Длина слова для поиска — 4 буквы (позволяет отбросить окончания слов)*/
{x=0;
do{
if(user_command[x]==what_to[0]&&user_command[x+1]==what_to[1]&&
user_command[x+2]=what_to[2]&&user_command[x+3]==what_to[3]) return 1;
x++;
}while(x<100);
}
/*А сейчас — функция input_()*/
void input_ (void)
{x=0;gotoxy(1,17);clreol();printf("-->Enter the command:");
/*Команда вводится в нижней области экрана, оставляя верхнюю для текста. Каждая новая команда стирает предыдущую */
do{
xy=getche();
user_command[x]=xy;
x++;
}while(xy!=13); /*13 — скан-код клавиши Enter*/
x=0;
}
//HAPPY END

Так вот. Если чего-то недопоняли, лучше вернитесь к этому месту сейчас. Лишний раз перечитайте код, чтобы трудности не возникли позже. Теперь, когда функции уже описаны, приступим к написанию собственно программы. Первое, что нужно сделать, это заставка. Не обязательно графическая. Сгодится, например, и такой вариант:

void main(void)
{
printf("_________________________\n");
printf("_______Neverland III_______\n");
printf("_____a text-adventure_____\n");
printf("___BY PUPKIN VASILY____\n");
printf("____All rights reserved_____\n");
printf("_________________________\n");
/*Далее исходники непосредственно игры*/
}

Выглядит, кстати, вполне сносно. Далее — сама игра. Ее создание — процесс очень творческий и интересный (даже лучше, чем битвы в Unreal :)).
Для начала разберемся с типами text-adventure. Вообще-то, классификацией игр этого жанра никто особо не занимался и заниматься не собирается, но каждый, кто играл хотя бы в несколько тестовых квестов, знает, что они бывают лабиринтовыми и линейными. Есть еще и третья категория — линейно-лабиринтовые (например, ТНЕ ADVENTURE OF GREAT HERO VASYA by Elf Dillm). Линейные квесты создаются по принципу: пока не пройдешь эту сцену, на следующую не попадешь. В лабиринтовых пользователю приходится блуждать по коридорам и собирать необходимые предметы. Линейно-лабиринтовые — это те, в которых встречаются как линейные сцены, так и лабиринтовые (впрочем, несложно было догадаться из названия).
Какую бы стезю вы ни выбрали, не увлекайтесь: едва ли кто-нибудь будет мучиться над непроходимым линейным квестом длиной 500 эпизодов. Навряд ли кто-либо хочет блуждать по восьмиэтажным лабиринтам, каждый этаж 100x100 клеток. Но оставим стилистику игры на ваше усмотрение и примемся за ее написание.
В принципе, всех указанных выше алгоритмов вполне достаточно, чтобы написать хороший линейный quest. Оформление и сюжет — дело вашего вкуса.
А вот с лабиринтами у нас все обстоит несколько иначе. Как правило, лабиринт задается таким образом:

char * lab[2][2];
lab[0][0]="описание локации 0x0
вашего лабиринта";
lab[1][0]="описание локации 1x0
вашего лабиринта";
lab[0][1]="описание локации 0x1
вашего лабиринта";
lab[1][1]="описание локации 1x1
вашего лабиринта";

Для перемещения по лабиринту можно использовать такой алгоритм:

int won=0, posx=1, posy=1;
do{
printf(o[posx][posy]);
ent();
if(find("east")= =1&&posx= =1)printf("No way any further!");
else if(find("west")= =1&&posx== 0)printf ("" No way any further!");
else if(find("sout")= =1"&&posy= =1)printf ("" No way any further!");
else if(find("nort")= =1&&posy= =0)printf (""No way any further!");
else if(find("east")= =1)posx++;
else if(find("west")= =1)posx--;
else if(find("sout")= =1)posy++;
else if(find("nort")= =1)posy--;
/*И еще, еще, еще строки кода */
}while(won= =0);

Пожалуй, это все. Удовольствие собственноручной разработки игры (с возможным использованием кусков кода, напечатанных в этой статье) оставляю вам. Единственный барьер, который может возникнуть у вас на пути — слабое знание С++. Но разве такая благородная цель, как написание собственной игры, не стоит нескольких недель усилий, направленных на изучение программирования? Впрочем, есть и еще одно ограничение — рамки вашего воображения. Но тут уже ничего не сделаешь…
Желаю творческих успехов.

P.S. Если вас не интересуют текстовые квесты, то можно, используя описанные выше функции find() и _input(), написать нечто вроде электронного собеседника — создать солидную базу данных слов и описать реакцию компьютера на их ввод.

Михаил Федотов aka $ky$pe@R

№ 54

Geek Bar Подвал

Перепечатка материалов разрешается только с указанием индексируемой ссылки на первоисточник.

Наши самые актуальные статьи вы найдете в газете "Виртуальные радости".