gamedev Tutorials Программирование игр

Каждый миг жизни наполнен какими-то событиями. События происходят вокруг нас, они могут происходить, на первый взгляд, сами по себе, а могут быть явным следствием каких-то причин. Однако, как бы не казалось «на первый взгляд», все события имеют какую-либо причину. Даже если вспомнить теорию «Большого взрыва», то можно предположить, что все, что происходит с нами сейчас, есть не что иное, как следствие этой самой «первопричины». Существует такая умозрительная теория, что если знать состояние всех частиц в какой-то момент времени, то можно предсказывать будущее ...

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

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

Вот тут мы подошли к одному из ключевых понятий, к «квесту». Что это такое? Это одновременно и жанр игры типа «приключение», и понятие помельче, означающее некое игровое задание, например, принести из Очень Темного Леса Очень Сладкое яблочко игровому персонажу. При написании игры этого жанра необходимо решать непростую задачу - каким-то образом учитывать исполнение заданий и выдача очередных поручений на основании уже решенных головоломок. Для этого и можно воспользоваться понятием «событие».

Каждый раз, когда игрок делает что-либо, происходит череда событий. Вот он нажал на клавишу - событие. Вот он убил страшного монстра - событие. Вот пошевелил мышью - тоже событие! Так какие же из них нам надо учитывать? Будь у нас Абсолютный Суперкомпьютер, способный заменить Реальность, мы бы на каждый квант времени «повесили» бы ярлык «событие» и со скоростью света обрабатывали бы все их, получив результате еще одну, вполне реальную Вселенную. Однако у нас всего лишь жалкий третий Пентиум! Очевидно, что нас не интересуют мелочи! Мы собрались писать игру, а это значит, что мы умеем выделять главное и не обращать внимания на частности (или должны уметь ...). Поэтому под событием будем понимать нечто значительное, например, выполнение квеста.

Для того чтобы работать в подобном, событийном мире, надо иметь возможность оперировать некими объектами, как и в любой подобной ситуации. Само собой напрашивается решение - объекты будут являться событиями. То есть, это некие control-ы, или, попросту - «контролы».

Для этого введем класс объектов, которые содержат в себе два основных метода - int control_activate() и int control_run(). Идея состоит в том, чтобы контрол мог «сработать» в определенной ситуации, то есть выполнить функцию control_run(). Для того чтобы контрол выполнил эту функцию, необходим "положительный" ответ от функции control_activate(). Функция control_activate() содержит в себе логическое выражение от некоего набора контролов, каждый из которых может возвращать количество срабатываний . А функция control_run() в ответ увеличит на 1 счетчик собственных срабатываний и выполнит какие-либо действия, предусмотренные сюжетом.

Пример:

Надо выполнить квест - убить хотя бы десять монстров в лесу, тогда старейшина деревни даст амулет.


// Простейший контрол №0, отвечающий за событие «убийство монстра»
// Просто увеличивается счетчик срабатываний контрола

int control_activate0000()
{
return TRUE;
}

int control_run0000()
{
return TRUE;
}

// - контрол №1, отвечающий за получение амулета,
// на основании контрола №0


int control_activate0001()
{
if( Control(0) >= 10) return TRUE;
		// - если убито десять или более
		// монстров, вернуть ИСТИНУ.
return FALSE;
}


int control_run0001()
{
Say("Молодец, ты справился с заданием!");    // - окно с фразой
GiveItToPlayer(ARTEFACT_AMYLET);             //- дать амулет игроку
return TRUE;
}

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

С помощью контролов можно решать самые разные задачи - от выполнения квестов до управления всевозможными триггерами/ловушками, дверьми и т.д., все, работу чего можно рассматривать как событие.

Жанровая принадлежность игры тут не играет ообой роли, так как выполнение заданий есть в любом жанре - в квестах, аркадах, РПГ, 3D-action ...

2000-12-25
Фролов Андрей ака FAL.

PMG  4 Января 2000 (c)  Фролов Андрей