Компьютерные игры. Как это делается

       

Избегайте статических классов и переменных


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

Статические переменные подобны глобальным, так как они доступны из большинства классов, но одновременно может существовать только один экземпляр такой переменной. Существует несколько классов, таких как ClassOperatingSystem, ClassGameSound и ClassFileSystem, которые действительно подразумевают наличие единственного экземпляра класса. Некоторые другие классы выглядят так, будто для них тоже должен существовать только один экземпляр, хотя иногда допускается наличие и нескольких экземпляров. Классический пример подобного статического класса - ClassGameWorld:

class ClassGameWorld

{

public:

// статические данные игрового мира

static void* m_GameWorldData;

// статические компоненты-функции

static bool Install(void);

static bool Remove(void);

static bool AddObject(GameObject& _obj);

};

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

Более правильным решением будет создать нестатическую версию класса ClassGameWorld, а затем завести статический шаблон списка игровых миров где-нибудь еще, например в классе ClassGame:

class ClassGame

{

private:

static TemplateList<ClassGameWorld*> m_GameWorldList;

public:

static ClassGameWorld& GetWorld(int _nWorld);

};

Это позволит программе иметь доступ ко многим экземплярам данного класса и в то же время сохранить только одно место для доступа ко всем данным игровых миров.

В главе 3 приведены общие советы Аллена Джексона по разработке игр.

Рагнар Шейерман (Ragnar Scheuermann), Wombat Games


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

Через полтора года большая часть команды была переброшена на Ultima Online, чтобы помочь в завершении этого проекта. Аккурат в это время один из программистов добавил в игру поддержку 3D-ускорителей. В качестве побочного эффекта этого шага было принято решение изменить перспективу камеры с изометрической на вид «из-за плеча» (как в Tomb Raider). Само собой, это разрушило часть модулей движка, потребовало переработки многих областей, не соответствующих новому положению камеры, и подготовило почву для следующего ключевого изменения. Сразу после выхода Ultima Online команда Ultima: Ascension была собрана вновь, но с новыми продюсером и ведущим дизайнером. Это привело к еще большему отходу от традиций Ultima 7, к более динамичной и активной игре. Работа над проектом пошла под девизом: «Больше удовольствия в каждые 30 секунд». Через год продюсер был уволен.

К этому моменту игра и управление проектом изменились до неузнаваемости, а от первоначальной команды (которая работала во время моего прихода) остались только шестеро бойцов: продюсер Ричард Гэрриот (Richard Garriott), программисты Герман Миллер (Herman Miller), Гэри Скотт Смит (Gary Scott Smith) и Чак Зок (Chuck Zoch), художники Скотт Джонс (Scott Jones) и Майкл Морлан (Michael Morlan). Движок... опять был переписан, и игра снова изменила направление, восстановив изначальные РПГ-черты. Вывод: проблемы с Ultima IX: Ascension возникли не потому, что проект не был хорош, а потому, что замыслы постоянно менялись.

А вот Ultima Online пострадала от недостаточно ясного видения игры, хотя и не так сильно. Концепция этого проекта никогда подробно не обсуждалась, поэтому игра выглядела по-разному в головах разных членов команды. Одни работали над имитацией виртуального мира, другие - над квестом, третьи находились под влиянием Diablo.


Куда больше игра претерпела от того, что вдруг изменились требования к тестированию, и вместо 100 тестеров на каждую миссию понадобилось 2500. К сожалению, срок завершения игры при этом остался прежним, и сокращать время пришлось за счет программистов, а не дизайнеров. В результате мы имеем то, что имеем: вышедшую с опозданием, полную ошибок игру, не имеющую явно выраженного жанрового направления. Код получился чрезвычайно сложным для использования, а все программисты, начинавшие его писать, покинули команду.

Сейчас мы работаем над новой игрой и прилагаем огромные усилия, чтобы дать ей хороший старт и все же реализовать возможности масштабной сетевой игры ролевого типа. Мы создаем виртуальный мир, где ничто не предписано заранее, а его главные обитатели - сами игроки. К слову, при проведении собеседования с кандидатами на участие в проекте наиболее важным был вопрос: «Согласны ли вы с подобной концепцией игры?»

Завершая разговор, Рагнар Шейерман вновь вернулся к проблеме концепции игры, сказав, что «тратит уйму усилий на построение желаемой технологической базы до начала работ над собственно игрой». Причины этого изложены выше. «Чтобы не пришлось ничего переделывать по мере появления текущих проблем».

Мэтт Притчард (Matt Pritchard), Ensemble Studios

Должность Мэтта Притчарда в Ensemble Studios - специалист по графическому движку и оптимизации. Мэтт участвовал в программировании Age of Empires, а в момент написания этой книги был всецело поглощен работой над Age of Empires II: The Age of Kings. Несмотря на плотный рабочий график, Мэтт нашел время, чтобы сказать несколько слов тем, кто мечтает программировать игры. Итак, о каких трех самых важных вещах должен помнить программист?

1. Невозможно написать эпическую сагу за ночь; упорство и настойчивость - вот лучшие инструменты.

2. Большинство задач уже было решено до вас; посмотрите, чему можно научиться у других.

3. Большинство проектов так и не завершается. Излишние амбиции и отсутствие реалистичной оценки возникающих задач обрекают их на скорое забвение.


Правильно оценивайте себя и соизмеряйте свои желания с реальными возможностями.

С какой самой сложной проблемой может столкнуться игровой программист? Мэтт Притчард делит программистские «тяготы» на две части.

• Идти в ногу с современными технологиями. Единственный способ добиться этого - сосредоточиться на самом важном, не жалея сил и времени на постоянное совершенствование.

• Строго контролировать ход работ. Программы должны создаваться вовремя и в соответствии с планом. Это приходит с опытом. Не вычеркивайте из помощников и соответствующую литературу по написанию надежного и «окончательного» кода. А вообще, это постоянная борьба, избежать которой, похоже, не удается никому.

В заключение Мэтт советует программистам, работающим над играми, выделить какую-то часть времени на регулярное и внимательное чтение группы новостей rec.games.programmer в Usenet, отражающей всю необходимую информацию о создании и совершенствовании игровых программ.

Чэд Фримен (Chad Freeman), Dreamforge Intertainment

Чэд Фримен - ведущий программист студии Dreamforge Intertainment, выпустившей в 1998 году великолепный квест Sanitarium. До этого проекта Чэд работал над играми Anvil of Dawn и Warwind.

В данном разделе Чэд предлагает игровым программистам несколько бесплатных советов и даже образец программы.

Вам, возможно, приходилось слышать, что при написании игровых программ одним из основных критериев является эффективность кода. Не верьте этому ни на минуту! Лишь для 10-20% вашей программы эффективность может оказаться критичной. Остальной код должен быть гибким, поскольку вам придется много раз его изменять. В противном случае, если код окажется слишком хрупок, чтобы допускать изменения, игра получится «второсортной».

Не стесняйтесь использовать что-либо по той только причине, что это придумано не вами. Многие замечательные решения, примененные в 3D-играх, основаны на технологиях, созданных для программ трехмерной визуализации несколькими годами ранее. Потратьте немного времени на исследование технических приемов, которые вы хотели бы использовать в своей игре.


Впоследствии это освободит вас для размышлений над по-настоящему уникальными аспектами игры.

Самое важное на первых порах - довести хоть что-нибудь до конца. Способность завершить игру - вот то, что будет отличать вас от тех героев, что начали, но не смогли... Один из моих приятелей, программист, любит повторять: «Завершить игру невозможно, можно лишь прекратить над ней работать». Всегда найдется что-то, что улучшит код, но однажды надо набраться смелости и сказать: «Хватит, он уже достаточно хорош», - и оставить игру в покое.

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

Ниже представлен пример реализации связанного списка через массив с указателем в сравнении с вариантом использования динамической памяти, а также небольшой пример, где противопоставлены эффективность и гибкость.

Пример массива:

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

Содержимое адресов памяти

001 [Указатель на первый элемент (010)]

002 [Указатель на последний элемент (062)]

...

010 [Указатель на графическое представление объекта]

011 [Здоровье]

012 [Указатель на следующий элемент (053)]

...

053 [Указатель на графическое представление объекта]

054 [Здоровье]

055 [Указатель на следующий элемент (098)]

...

062 [Указатель на графическое представление объекта]

063 [Здоровье]

064 [Указатель на NULL (конец списка)]

...

098 [Указатель на графическое представление объекта]

099 [Здоровье]

100 [Указатель на следующий элемент (062)]



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

При использовании массива реализация может выглядеть следующим образом:

Заголовок списка:

Первый [индекс первого объекта - 001]

Последний [индекс последнего объекта - 003]

Список:

Индекс массива - данные - индекс следующего элемента

001 Данные объекта 1 002

002 Данные объекта 4 004

003 Данные объекта 2 -1

004 Данные объекта 3 003

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

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

И еще несколько слов о гибкости:

Это то, с чем вы сталкиваетесь всякий раз, когда создаете игру. По сути, программируя, вы пытаетесь предсказать будущее и неизбежно делаете предположения, которые в дальнейшем окажутся неверными. Однако предположения могут быть как хорошими, так и плохими. В Warwind мы решили, что каждая машина должна иметь точное представление о состоянии игры в каждом кадре. Это было неудачное предположение, поскольку в Интернете, где время ожидания велико, а потеря пакетов - обычное дело, синхронизация каждого кадра замедляет игру до скорости улитки.

Чтобы знать все о компании Dreamforge Intertainment, ее служащих и играх, обратитесь на веб-сайт www.dreamforge.com.

Стюарт Денман (Stuart Denman), Surreal Software

Стюарт Денман - вице-президент и технический директор Surreal Software, многообещающей компании, ответственной за игру Drakan (издатель Psygnosis).

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


Содержание раздела