Программирование стратегических игр с DirectX 9.0

         

Программирование стратегических игр с DirectX 9.0


Программирование стратегических игр с DirectX 9.0


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

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

Первые стратегические игры.









Программирование стратегических игр с DirectX 9.0


Краткий обзор


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

Архитектура программ Windows. Как создать программу для Windows.

Если вы знакомы с программированием в Windows, можете пропустить эту главу. Если нет — усаживайтесь поудобнее, расслабьтесь и наслаждайтесь представлением.





Программирование стратегических игр с DirectX 9.0


Краткий обзор


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

Основы построения сюжета. Расстановка целей. Боевые единицы. Управление ресурсами. Дерево технологий. Игровая кампания. Многопользовательская игра.

Программирование стратегических игр с DirectX 9.0


Краткий обзор


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

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

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

Фаза идей. Фаза определения требований. Фаза технической документации. Фаза разработки. Фаза тестирования. Фаза производства. Распространение.

Программирование стратегических игр с DirectX 9.0


Краткий обзор


Одним из ключевых моментов разработки стратегической игры является создание ландшафтной библиотеки. Учтиывая, что действие большинства стратегических игр происходит на поверхности земли, ландшафт приобретает очень важное значение. Существуют тысячи способов работы с ландшафтом, одним из которых является метод блочной графики. В данной главе я опишу следующие аспекты блочной графики для стратегических игр:

Основы блочной графики. Многослойные блоки. Редактирование и хранение блоков. Свойства блоков. Визуализация блоков. Визуализация блоков.

Программирование стратегических игр с DirectX 9.0


Краткий обзор


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

Определение требований к интерфейсу. Удобство интерфейса. Двухмерная графика в Direct3D. Горячие точки.

Программирование стратегических игр с DirectX 9.0


Краткий обзор


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

В этой главе я рассмотрю следующие темы:

Проектирование подразделений. Программирование шаблона. Отображение подразделений. Загрузка и создание подразделений.

Активные зоны и графика


Взгляните на начало схемы. Обратите внимание, что она начинается со стартовой заставки игры. В большинстве игр отображение заставки можно прервать, щелкнув мышью по кнопке на экране или нажав клавишу на клавиатуре. В схеме я описал кнопку на экране, которая позволяет игроку перейти от заставки к главному меню. Рядом с описанием кнопки я поместил индикатор «mzone», сообщающий что это будет активная зона для мыши. Активной зоной называется область экрана, по которой пользователь может щелкнуть мышью, чтобы были выполнены какие-то действия. Графика стартового экрана игры присутствует в схеме как отдельный элемент. Рядом с ним я поместил индикатор «bmp», указывающий, что это графический элемент.

Далее следует блок для главного меню игры. Оно содержит четыре кнопки с активными зонами: одна для начала новой игры, одна для загрузки существующей игры, одна для записи текущей игры и одна для выхода из программы.

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

Исследуя схему дальше, мы встречаем интерфейс загрузки игры. Здесь я описал графический элемент, содержащий список сохраненных ранее игр. Я также перечислил текстовое поле для ввода имени файла, кнопку загрузки и кнопку возврата к главному меню. Есть еще несколько активных зон, которые я не упомянул в схеме. Можете добавить их? Ответ будет дан чуть позже.

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

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

Вот что можно сказать о схеме интерфейса игры «Крестики-нолики». Она весьма обширна, несмотря на то, что «Крестики-нолики» — это очень простая игра. А теперь попробуйте вообразить как будет выглядеть схема интерфейса для игры из серии Command & Conquer. Ах, вы интересуетесь, что я пропустил в интерфейсе загрузки игры? Я пропустил графические элементы и активные зоны, которые позволят игроку прокручивать список записанных игр. Что делать, если список всех сохраненных игр не помещается на одном экране? Итак, вам потребуется полоса прокрутки и реагирующие на щелчки мыши области для кнопок. Вы могли подумать и о многих других элементах, которые я также не учел. Теперь напишите вашу собственную схему интерфейса для игры «Тетрис», и посмотрите, что получилось. Выможете быть удивлены сложностью этой схемы.



Анимированные блоки


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

Так как же выполнить анимацию блоков? Один из простейших методов — выделить для выполнения анимации какой-нибудь диапазон блоков. Предположим, для выполнения анимаций мы выделили блоки с 1 по 100, и каждая анимационная последовательность будет состоять из 10 кадров. Это дает вам 10 анимированных блоков с 10 кадрами в каждой анимации. Если в цикле визуализации встречается блок с номером 0, 10, 20, 30, 40, 50, 60, 70, 80 или 90, программа прибавляет к номеру блока номер текущего кадра анимации, чтобы получить номер того блока, который должен быть выведен. Когда счетчик кадров анимации достигает значения 10, он сбрасывается в 0 и цикл анимации снова повторяется с самого начала. Взгляните, например, на следующий псевдокод:

Anim_Frame = 0; Loop Start = 0; Loop < #TilesToDisplay; Loop++ // Визуализация анимированных блоков If(Current_Tile.type == TYPE_ANIMATION) RenderTile(Current_Tile.value + Anim_Frame); // Визуализация обычных блоков Else RenderTile(Current_Tile.value); // Увеличение счетчика кадров Anim_Frame++; If(Anim_Frame == 10) Anim_Frame = 0; Loop Repeat

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



Архитектура DirectMusic


DirectX содержит два интерфейса, которые можно применять для воспроизведения звуковых файлов: DirectSound и DirectMusic. Главное различие между ними заключается в том, что DirectSound предоставляет низкоуровневый доступ к аппаратуре звуковой карты. Лично я предпочитаю использовать DirectMusic, поскольку он предоставляет более широкие возможности и достаточно быстро работает на современных процессорах. DirectMusic содержит следующие основные части:

Загрузчик Исполнитель Сегменты

Архитектура проекта D3D_MouseZoneHighlights


Проект содержит четыре уникальных файла: main.cpp, main.h, MouseZoneClass.cpp и MouseZoneClass.h. Данный пример программы является усовершенствованной версией проекта D3D_MouseZones в которой сделано не так уж и много изменений.

Для программы необходимы следующие библиотеки: d3d9.lib, dxguid.lib, d3dx9dt.lib, d3dxof.lib, comctl32.lib и winmm.lib.



Архитектура проекта D3D_MouseZones


Проект содержит четыре уникальных файла: main.cpp, main.h, MouseZoneClass.cpp и MouseZoneClass.h. Файлы с кодом класса для реализации активных зон являются основным отличием этого проекта от предыдущего.

Программе необходимы следующие библиотеки: d3d9.lib, dxguid.lib, d3dx9dt.lib, d3dxof.lib, comctl32.lib и winmm.lib.



Архитектура проекта D3D_TitleScreen


Проект содержит два уникальных файла: main.cpp и main.h. Остальные, включенные в проект файлы, — d3dfont.cpp, d3dutil.cpp и dxutil.cpp, — являются частью Microsoft DirectX 9.0 SDK. Вы заметили, что список короче чем раньше? Это из-за того, что данный пример не использует предоставляемый Microsoft каркас приложения DirectX. В данном проекте мы воспользуемся лишь несколькими вспомогательными файлами для выполнения действий не имеющих отношения к каркасу приложения.

Программе необходимы библиотеки d3d9.lib, dxguid.lib, d3dx9dt.lib, d3dxof.lib, comctl32.lib и winmm.lib.



Архитектура проекта D3DFrame_Isometric2DSpriteTiles


Проект содержит два уникальных файла: main.cpp и main.h. Остальные включенные в проект файлы, — d3dapp.cpp, d3denumeration.cpp, d3dfont.cpp, d3dsettings.cpp, d3dutil.cpp и dxutil.cpp, — являются частью Microsoft DirectX 9.0 SDK. Снова используется каркас приложения DirectX.



Архитектура проекта D3DFrame_2DTiles


Проект содержит два уникальных файла: main.cpp и main.h. Остальные включенные в проект файлы, — d3dapp.cpp, d3denumeration.cpp, d3dfont.cpp, d3dsettings.cpp, d3dutil.cpp и dxutil.cpp, — являются частью Microsoft DirectX 9.0 SDK.

Уникальные файлы я создал специально для этого примера. Вы можете обратить внимание на префикс D3DFrame у названия проекта. Он означает, что при создании программы я пользовался предоставляемым Microsoft каркасом приложения Direct3D. Каждый раз, когда вы увидите этот префикс, знайте, что я использовал каркас приложения. Если вам не нравятся подобные каркасы, не волнуйтесь, — я покажу как выполнить ту же самую работу не применяя их.

Структура проекта показана на Рисунок 5.39.



Архитектура проекта D3DFrame_3DTiles


Проект содержит два уникальных файла: main.cpp и main.h. Остальные включенные в проект файлы, — d3dapp.cpp, d3denumeration.cpp, d3dfile.cpp, d3dfont.cpp, d3dsettings.cpp, d3dutil.cpp и dxutil.cpp, — являются частью Microsoft DirectX 9.0 SDK.

Обратите внимание, что название одного из файлов выделено полужирным шрифтом. Файл d3dfile.cpp отсутствовал ранее и был добавлен только к этому проекту. Его назначение — помогать загружать файлы формата .x, содержащие информацию о трехмерных объектах. Он необходим для загрузки трехмерных моделей, созданных в таких пакетах визуального моделирования, как Maya, 3D Studio MAX и MilkShape. Если хотите, вы можете написать собственный загрузчик моделей, но встроенные функции, предоставляемые файлом d3dfile.cpp сделают вашу жизнь намного проще.



Архитектура проекта D3DFrame_Isometric2DTiles


Проект содержит два уникальных файла: main.cpp и main.h. Остальные включенные в проект файлы, — d3dapp.cpp, d3denumeration.cpp, d3dfont.cpp, d3dsettings.cpp, d3dutil.cpp и dxutil.cpp, — являются частью Microsoft DirectX 9.0 SDK. Звучит знакомо, а? Вы должны заметить повторяющуюся тему в программах, написанных с использованием каркаса приложения Direct3D. Я пытаюсь оставить вещи настолько простыми, насколько это возможно, и буду так же поступать в дальнейшем.



Архитектура программ Windows


Если вы до Windows работали с другой операционной системой, такой как UNIX, Linux или DOS, новый стиль программирования может показаться несколько необычным. Сначала придется отказаться от функции main(), которая будет заменена функцией с именем WinMain(). Так же как в других операционных системах требовалось наличие функции main(), программам работающим в Windows необходима функция WinMain().



Атака ядерных ракет на игрока GDI ©2002 Electronic Arts All Rights Reserved





Как я упоминал ранее, NOD обладает также замечательной обороной. Одно из таких оборонительных сооружений называется Рука NOD. Это башня с лазером, который может разрушить большинство врагов за один выстрел. Обратная сторона такой защиты — большое потребление энергии и слабая защищенность против большого количества врагов. Вы можете увидеть как действует это оружие на Рисунок 1.11.



Баланс игры


Я полагаю, что одна из отличительных черт, выделяющих C&C, это возникающее чувство сбалансированности. По моему мнению Command & Conquer одна из наиболее сбалансированных игр. Вы не можете выиграть с помощью одного типа подразделений или единственного типа стратегии. Кажется, почти все в игре имеет свою Немезиду.

Вы должны бороться за сбалансированность, программируя любые типы стратегических игр. Если вы допустите несбалансированность, игроки быстро найдут ее и воспользуются ею. Это ясно видно в таких играх, как Total Annihilation от Cavedog Entertainment. В Total Annihilation выигрывает тот, кто первым построит большие воздушные силы. Самолеты передвигаются слишком быстро, и нет способа для их эффективного уничтожения.

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



Баланс ресурсов


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



Базовая карта изометрических блоков





Фактически, карта для изометрических блоков является картой для двухмерных блоков, повернутой на 45 градусов по двум осям. Это создает интересную сетку, поскольку с точки зрения зрителя блоки теперь кажутся повернутыми. Поскольку карта развернута, координаты X и Y теперь не соответствуют экранным координатам X и Y. На Рисунок 5.11 новые оси соответственно помечены. Обратите внимание, что ось X направлена от середины верхней части экрана к к его нижнему правому углу. Ось Y начинается также в середине верхней части экрана, но направлена к нижнему левому углу. В результате блок с координатами 0,0 расположен в центре верхней части экрана. Не слишком простой метод отображения!

Как только мы разместили начальный блок с координатами 0, 0, достаточно легко вывести алгоритм дальнейшего рисования. Он практически тот же, что использовался для отображения двухмерных блоков, за исключением того, что координаты блоков слегка изменились. Взгляните на Рисунок 5.12, чтобы увидеть, в каком порядке отображаются изометрические блоки.



Благодарности


Джим Хилл (Jim Hill) и Вес Бесквит (Wes Beckwith) из Wordware Publishing за издание этой книги. Бет Кохлер (Beth Kohler) и Хитер Хилл (Heather Hill) из Wordware за редактирование книги и допечатную подготовку. Гил Шиф (Gil Shif) из Blizzard Entertainment за помошь в получении разрешения на использование изображений из их игр. Эми Фэррис (Amy Farris) из Westwood Entertainment за помошь в получении разрешения на использование изображений из их игр. Джефф Ройл (Jeff Royle) из ATI за предоставление видеокарт для проверки совместимости. Сара Дэвис (Sarah Davis) из Discreet за помощь в работе над материалом о 3ds Мax. Сьюзан Доэринг (Susan Doering) из Adobe за помощь в работе над материалом о Photoshop.



Блочная карта из 100 элементов





В приведенном выше фрагменте кода я очищаю карту, заполняя ее блоками с номером 0. Это общепринятая практика, поскольку блок с номером 0 является базовым блоком для визуализации. Обычно этот блок содержит изображение земли или даже является специальным блоком-пустышкой. Блок-пустышка — это обычный блок, на котором расположена предупредительная надпись, например «НЕ ИСПОЛЬЗУЕТСЯ». Наличие такого блока позволяет сразу увидеть те области карты, блоки которых не были инициализированы.

Итак, теперь у вас есть двухмерный массив блоков. Как изменить блок? К счастью, очень просто. Скажем, вы хотите изменить блок, расположенный на два блока левее и на три блока ниже начала карты, чтобы его значение было равно 15. Для этого достаточно написать следующий код:

iTileMap[2][3] = 15;

Все, что надо сделать — присвоить желаемое значение расположенному в требуемой позиции элементу массива.

Взгляните на следующий код и попробуйте представить, как будет выглядеть полученная в результате карта. Подсказка: блок с номером 15 изображает заштрихованный квадрат, а блок с номером 0 — пустой квадрат.

// Сверху вниз iTileMap[0] [0] = 15; iTileMap[0] [1] = 15; iTileMap[0] [2] = 15; iTileMap[0] [3] = 15; iTileMap[0] [4] = 15; // Слева направо iTileMap[1] [4] = 15; iTileMap[2] [4] = 15; iTileMap[3] [4] = 15; // Снизу вверх iTileMap[3] [3] = 15; iTileMap[3] [2] = 15; iTileMap[3] [1] = 15; iTileMap[3] [0] = 15; // Справа налево iTileMap[2] [0] = 15; iTileMap[1] [0] = 15;

Ответ показан на Рисунок 5.32.



Блочная карта из травы и песка





Первое, что бросается в глаза, — ужасный вид этой карты! Блоки с изображением песка и травы выделяются как 100-летний финалист на QuakeCon. Причина заключается в том, что нет никаких блоков, изображающих плавный переход от травы к песку. Переходные блоки — прошу на сцену.

Добавив к карте, изображенной на Рисунок 5.17 несколько блоков с дополнительными деталями, вы получите гораздо лучший результат смешивания текстур, изображенный на Рисунок 5.18.



Блочная карта с двумя слоями





Первый слой карты содержит два типа блоков с изображанеием травы. Второй слой карты содержит блоки с изображением камней. Взгляните на код, предназначенный для генерации такой карты:

// // Установка базовых блоков // // Вертикаль for(int i = 0; i < 10; i++) { // Горизонталь for(int j = 0; j < 10; j++) { // Случайный выбор базового блока iTileMap[i][j][0] = rand() % 2; } } // // Добавляем блоки с деталями // iTileMap[5][5][1] = 3; iTileMap[3][9][1] = 3; iTileMap[1][7][1] = 3; iTileMap[8][8][1] = 3; iTileMap[6][3][1] = 3; iTileMap[4][1][1] = 3;

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

В следующем слое вручную размещаются блоки с изображением камней. Положение блока в массиве определяется заданными координатами [x][y][z], где координата z отвечает за слой, в котором будет находиться блок. Задавая значение z равным 1, мы указываем игре, что изображения камней помещаются во втором слое.



Блочная карта с плавными переходами от травы к песку





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

Сперва нам потребуются блоки для переходов от травы к песку в направлении с севера на юг. Они обеспечивают приятно выглядящие переходы горизонтальных линий блоков, что иллюстрирует Рисунок 5.19.



Блок с изображением травы с камнями на ней





Блок на Рисунок 5.15 содержит и текстуру травы и текстуру камней. Это прекрасно и хорошо работает, но что случится, когда для разнообразия вы решите добавить другие фоновые блоки, например с изображением песка? В результате вам потребуется создавать новый блок и изображением камней на песке. Теперь у вас есть четыре блока: песок, трава, камни на песке и камни на траве.

Рисунок 5.16 показывает, как использование слоев решает проблему и приводит к менее интенсивному расходованию ресурсов.



Блоки для переходов в направлении с юга на север





В левой части Рисунок 5.19 изображен блок в верхней части которого (на севере) изображена трава, а в нижней части (на юге) расположена прозрачная область. Накладывая изображение травы на тестуру с изображением песка, получаем замечательный результат. Этот же подход остается правильным и для блока в правой части рисунка. Просто в этом случае изображение травы расположено внизу (на юге), а прозрачная область — сверху (на севере). Рассмотренные блоки охватывают первые два сценария перехода.

Теперь у нас есть блоки, обеспечивающие плавную смену текстуры в направлении с севера на юг. Следующий шаг — обеспечить аналогичную смену текстур в направлении с востока на запад. Это делают блоки, изображенные на Рисунок 5.20.



Блоки для переходов в направлении с востока на запад





На блоке, изображенном в левой части рисунка, трава расположена слева (на западе), а прозрачная часть — справа (на востоке). Затем изображение накладывается на текстуру с изображением песка. Как обычно, это замечательно работает и для блоков, на которых трава располагается с правой стороны. Здесь мы не узнали ничего нового, только рассмотрели следующие два сценария перехода.

Возможно, вы думаете, что на этом работа закончена. А как насчет углов? Правильно, вам еще необходимы угловые блоки для соединения блоков с переходом изображения с севера на юг и блоков с переходом изображения с востока на запад. Обратите внимание на четыре угла, изображенных на Рисунок 5.21.



Блоки разных размеров визуализированные без смещения





Обратите внимание, что все блоки, кроме деревьев на Рисунок 5.37 выглядят замечательно. Деревья же букавльно протыкают ландшафт. Это объясняется тем, что визуализация верхней границы дерева начинается в обычной позиции, но само изображение дерева слишком высокое. Чтобы решить эту проблему вы должны при визуализации деревьев учитывать смещение. Чтобы вычислить смещение, возьмите высоту обычных блоков и вычтите из нее высоту блока с изображением дерева. В приведенном примере высота дерева равна 64 пикселам, а высота обычного блока — 32 пикселам. Таким образом, смещение будет равно 32 – 64 = –32 пиксела. Теперь, при отображении вашей карты, все деревья будут выводиться в позиции Y + –32. Это перемещает изображение деревьев при визуализации на 32 точки вверх. Если желаете, можете выполнять подобные изменения, добавляя смещения по осям X и Z. В основном данный метод используется для выравнивания блоков, которые не вписываются в стандартный размер блоков, принятый в вашей игре.



Блоки с изображениями дорог


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

Предположим, игрок занят расширением своей империи в вашей игре, и он хочет построить новую дорогу. Что произойдет, если он разместит блок с изображением дороги рядом с еще одним (или не одним) таким же? Будете ли вы проверять все присутствующие на карте блоки с изображением дорог, чтобы посмотреть как они изменены? Будете ли вы проверять блоки, размещенные вокруг нового добавляемого блока, чтобы посмотреть не требуют ли они изменения? Решения, решения! Чтобы лучше проиллюстрировать рассматриваемую концепцию, я привожу Рисунок 5.25.



Блокировка буфера вершин


Следующая вызываемая в программе функция называется IDirect3DVertexBuffer9::Lock(). Она блокирует только что созданный буфер вершин для редактирования. В трехмерной визуализации буфер вершин нельзя редактировать сразу как захочется. Прежде, чем начать редактироывать содержимое буфера, вы должны заблокировать его. Это действие гарантирует, что данные не будут использоваться, пока вы их редактируете. Это необходимо сделать потому, что у видеокарты есть собственный процессор. Вот как выглядит прототип функции блокировки:

HRESULT Lock( UINT OffsetToLock, UINT SizeToLock, VOID **ppbData, DWORD Flags );

К счастью, параметры этой функции не слишком сложны. Первый из них, OffsetToLock, задает номер байта в буфере вершин с которого начинается блокировка. Он очень полезен, когда надо отредактировать часть буфера вершин не блокируя его весь. Если вы не хотите задавать смещение, укажите значение 0.

Второй параметр, SizeToLock, указывает количество байт, блокируемых в буфере вершин. Если вы хотите заблокировать весь буфер, укажите значение 0.

Третий параметр, ppbData, является указателем на блокируемый буфер вершин. Ничего себе имечко у него!

Четвертый параметр, Flags, определяет параметры блокировки. В рассматриваемом примере никакие флаги не используются, но я все равно приведу описание доступных флагов в таблице 6.9.

Таблица 6.9. Значения D3DLOCK

Значение Описание
D3DLOCK_DISCARD Приложение переписывает значения пользуясь только операциями записи. Этот метод применяется когда используются динамические данные, такие как динамические текстуры, и буферы вершин
D3DLOCK_NO_DIRTY_UPDATE Оберегает систему от изменения грязных областей данных. Флаг используется достаточно редко
D3DLOCK_NOSYSLOCK Предотвращает остановку действий системы, таких как перемещение курсора мыши, на время блокировки. Рекомендуется использовать, когда выполняется длительная по времени блокировка.
D3DLOCK_READONLY Буфер доступен только для чтения
D3DLOCK_NOOVERWRITE Система немедленно возвращается из функции блокировки, поскольку приложение обязуется не перезаписывать содержимое буфера. Этот вариант работает быстрее, чем блокировка только для чтения

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



Боевые единицы


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

Во всех связанных с военными действиями стратегических играх есть боевые подразделения. Некоторые игры, подобно Total Annihilation содержат сотни подразделений, а другие обходятся всего несколькими. Я не устану повторять, что ключ здесь — баланс. Поскольку вы пока находитесь на самых начальных стадиях разработки вашей собственной стратегической игры, надо с чего-то начинать. Я предлагаю сперва сосредоточиться на единственной, наиболее интересной вам боевой единицы. Кроме того, следует выбрать такое подразделение, существование которого не зависит от других. Самолет для авианосца был бы не самым лучшим выбором, гораздо лучшим вариантом является танк.

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



Броня боевых единиц


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



Будущее стратегий реального времени


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



Цели миссий


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

Миссии не должны быть тривиальными заданиями, чтобы игрок просто сделал что-нибудь. Вместо этого они должны служить развитию сюжета и продвижению по нему игрока. Помните об этом, когда будете выписывать структуру миссий.

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

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



Что такое блок?


Те, кого мучает этот вопрос, должны спросить себя. Шутка. Если серьезно, блок ни что иное, как кирпичик для строительства ландшафта. Подобно тому, как обычные строительные кирпичи по отдельности не представляют ничего особенного, блоки также достаточно просты. Чтобы получить имеющий смымсл результат, вы должны разместить вместе несколько блоков.

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



Command & Conquer от Westwood


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



Command H Q


Еще одна из моих любимых старых стратегических игр называется Command H.Q. Ее разработала Ozark Softscape, — небольшая домашняя команда разработчиков из Арканзаса. Наш мир настолько тесен,что один из разработчиков из Ozark, Марк Ботнер, теперь работает со мной (привет, Марк!).

В Command H.Q. вы сражаетесь один на один с другим игроком или против компьютера. Игра очень похожа на Empire, где вы завоевываете города, создаете воинские подразделения и совершаете набеги на вражескую территорию. Особенность игры заключается в том, что вы можете выбирать временной период, в который происходит игра. Если вы выберете прошедшие года, например 1918, то будете играть со старой технологией. Если вы выберете будущее, скажем 2023 год, в игре будут доступны войска будущего. Кроме того, игра поддерживает многопользовательский режим с соединением компьютеров через модем или через последовательный кабель.

В Command H.Q. есть несколько зацепок для привлечения внимания игрока. Во-первых — это управление ресурсами. Это одна из первых игр, в которые я играл, где в общую картину добавлена экономика. Контроль над месторождением нефти имеет такую же стратегическую ценность, как контроль над важным аванпостом. Второй приманкой является многопользовательский режим. Искуственный интеллект игры достаточно слаб, но многопользовательский режим компенсирует это недостаток, позволяя играть с живым соперником.



Данные местоположения


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

Точка 1 — (0,0,0)

Точка 2 — (0,10,0)

Точка 3 — (10,0,0)

Взгляните на Рисунок 6.9, чтобы увидеть образованный этими точками треугольник.



Данные нормали


Затем я объявляю данные, содержащие информацию о нормали грани. Нормали в трехмерной визуализации задают направление, в котором направлена грань. Эти данные необходимы для трехмерного освещения, поскольку аппаратура должна знать, как изображать освещение грани. Данные нормали хранятся в виде набора трех координат, так же, как и данные местоположения. Поэтому я снова использую значение типа D3DXVECTOR3. Чтобы увидеть нормаль, взгляните на Рисунок 6.10.



Данные текстуры


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

Direct3D представляет информацию о координатах текстуры в виде декартовых координат на плоскости. Другими словами координаты текстуры содержат два числа — одно для оси X и одно для оси Y. Главное отличие координат текстуры заключается в том, что диапазон допустимых значений для них ограничен. Они могут принимать значения в диапазоне от 0.0 до 1.0. Это объясняется тем, что указываются относительные координаты, а реальные будут зависеть от размера изображения текстуры. Возьмем текстуру размером 16 на 16 точек. Координаты текстуры (0.5, 0.5) будут соответствовать центру текстуры с реальными координатами точки (8, 8). В случае текстуры размером 32 на 32 точки те же самые координаты текстуры будут соответствовать центру текстуры с реальными координатами (16, 16). Эту концепцию иллюстрирует Рисунок 6.11.



Дерево технологий


Если ресурсы являются сердцем стратегии реального времени, то дерево технологий — это ее скелет. Все происходящее в стратегии реального времени зависит от дерева технологий. Если вы не знакомы с этим понятием, поясню, что дерево технологий определяет эволюцию технологий в стратегии реального времени. Взгляните, например на упрощенное дерево технологий, приведенное на Рисунок 3.7.



Деструктор SoundSystem ~SoundSystem()


В следующем блоке кода представлен деструктор класса:

SoundSystem::~SoundSystem() { SAFE_RELEASE(m_pLoader); SAFE_RELEASE(m_pPerformance); }

Деструктор освобождает объекты загрузчика и исполнителя. Я использую вспомогательный макрос DirectX с именем SAFE_RELEASE. Он проверяет равно ли значение указателя NULL и, если нет, освобождает объект. Поэтому данная операция и называется безопасным освобождением. Раз в классе создаются объекты загрузчика и исполнителя, в деструкторе их следует освободить.



Детализация схемы интерфейса


Пока я лишь показал вам наипростейший проектный документ для интерфейса. Как насчет чего-нибудь более стимулирующиего? Есть еще несколько элементов, необходимых для хорошей схемы проекта интерфейса. Вот список некоторых из них:

Взаимосвязи. Звук. Состояние.

Диалоговое окно для выбора типа добавляемого к проекту файла




Фактически это то же самое диалоговое окно, что и изображенное на Рисунок 2.3, просто в нем выбрана другая вкладка. Вместо того, чтобы выбирать тип создаваемого проекта, сейчас мы будем выбирать тип добавляемого файла. Больше всего нас должны интересовать типы C/C++ Header File и C++ Source File. Перед тем, как продолжить, выберите тип C++ Source File.

Мы уже на финишной прямой, но еще не закончили. Перед тем, как щелкнуть по кнопке OK, вы должны задать имя создаваемого файла. Введите в качестве имени файла CreateWindow и щелкните по кнопке OK.

ПРИМЕЧАНИЕ Вы не обязаны давать исходному файлу и проекту одинаковые имена. Я делаю это только ради организации информации. Не стесняйтесь называть файл с исходным кодом, как вы желаете. (Некоторые люди используют имя Main.) СОВЕТ Когда вы создаете новый файл для проекта к нему добавляется требуемое расширение. Вам не надо вводить его. Например, если вы создадите файл с исходным кодом C++ и укажете имя Main, на жестком диске он будет сохранен как файл Main.cpp.

Теперь, когда файл создан и добавлен к проекту, вы можете видеть его в окне рабочего пространства. Взгляните на Рисунок 2.8.



Диалоговое окно подтверждения выбранных параметров





Представленное диалоговое окно не содержит ничего необычного. Оно выводится только для того, чтобы вы могли удостовериться, что будет создан проект желаемого типа. Для продолжения работы щелкните по кнопке OK.