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

         

Заголовочный файл Main h


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

#define STRICT #include <windows.h> #include <commctrl.h> #include <commdlg.h> #include <math.h> #include <tchar.h> #include <stdio.h> #include <D3DX9.h> #include "DXUtil.h" #include "D3DEnumeration.h" #include "D3DSettings.h" #include "D3DApp.h" #include "D3DFont.h" #include "D3DUtil.h" // Структура для данных вершин блока struct TILEVERTEX { D3DXVECTOR3 position; // Позиция D3DXVECTOR3 vecNorm; // Нормаль FLOAT tu, tv; // Координаты текстуры (U,V) }; // Наш собственный FVF, описывающий созданную структуру данных вершин // D3DFVF_XYZ= Информация о координатах // D3DFVF_NORMAL = Информация о нормалях // D3DFVF_TEX1 = Информация о текстуре #define D3DFVF_TILEVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) class CD3DFramework : public CD3DApplication { // Шрифт для отображения FPS и данных видеорежима CD3DFont* m_pStatsFont; // Массив целых чисел для хранения блочной карты int m_iTileMap[100]; short m_shTileMapWidth; short m_shTileMapHeight; // Буфер для хранения текстур LPDIRECT3DTEXTURE9 m_pTexture[32]; // Размеры окна short m_shWindowWidth; short m_shWindowHeight; // Буфер для хранения вершин LPDIRECT3DVERTEXBUFFER9 m_pVBTile; protected: HRESULT OneTimeSceneInit(); HRESULT InitDeviceObjects(); HRESULT RestoreDeviceObjects(); HRESULT InvalidateDeviceObjects(); HRESULT DeleteDeviceObjects(); HRESULT Render(); HRESULT FinalCleanup(); HRESULT CreateD3DXTextMesh(LPD3DXMESH* ppMesh, TCHAR* pstrFont, DWORD dwSize); // Создание буфера вершин блока void vInitTileVB(void); // Рисование блока на экране void vDrawTile(float fXPos, float fYPos, float fXSize, float fYSize, int iTexture); public: LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); CD3DFramework(); };

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

struct TILEVERTEX { D3DXVECTOR3 position; // Позиция D3DXVECTOR3 vecNorm; // Нормаль FLOAT tu, tv; // Координаты текстуры (U,V) };

ПРИМЕЧАНИЕ Действительно, в названии программы присутствует слово 2D, но не позволяйте ему одурачить вас. DirectX больше не работает с чисто двухмерной графикой, так что теперь программы используют трехмерную графику, которая выглядит как двухмерная. По этой причине я создал структуру для описания вершин, содержащую информацию, необходимую для создания трехмерного блока, который будет выглядеть как имеющий только два измерения. Если вы хотите получить больше информации об этом аспекте программирования, я рекомендую вам обратиться к главе 6, которая сосредотачивается на программировании двухмерной графики в трехмерном окружении.

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

К заслуживающим упоминания переменным класса относятся m_iTileMap, m_shTileMapWidth, m_shTileMapHeight, m_pTexture и m_pVBTile. Массив m_iTileMap хранит информацию блочной карты. Я объявляю массив из 100 целых чисел, поскольку ширина и высота карты будут равны 10 блокам.

Переменные m_shTileMapWidth и m_shTileMapHeight хранят размеры блочной карты. В конструкторе класса я присваиваю этим переменным значение 10.

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

Указатель m_pVBTile указывает на буфер вершин, необходимый программе для визуализации блоков.

Следующий блок кода, который мы рассмотрим более подробно, выглядит так:

// Создание буфера вершин блока void vInitTileVB(void); // Рисование блока на экране void vDrawTile(float fXPos, float fYPos, float fXSize, float fYSize, int iTexture);

Эти два прототипа функций являются сердцем рассмартиваемого примера, поскольку именно они относятся к отображению блоков. Первая функция, vInitTileVB(), инициализирует буфер вершин блока, используемый для визуализации. Следующая функция, vDrawTile(), применяется для отображения блока на экране.

ПРИМЕЧАНИЕ Код, который вы видите здесь, не является точной копией кода из файла с сопроводительного компакт-диска. Чтобы сэкономить место в книге, я удалил из кода некоторые комментарии.

И снова наше внимание будет сосредоточено только на одном заголовочном файле — main.h. Раньше вы уже видели большую часть содержимого этого файла, поэтому я сконцентрируюсь на наиболее важных фрагментах. Первый из таких фрагментов — объявление переменных класса:

// Массив целых чисел для хранения карты int m_iTileMap[100][2]; short m_shTileMapWidth; short m_shTileMapHeight; // Буфер для хранения текстур LPDIRECT3DTEXTURE9 m_pTexture[32];

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

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




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

#define STRICT #include <windows.h> #include <commctrl.h> #include <commdlg.h> #include <math.h> #include <tchar.h> #include <stdio.h> #include <D3DX9.h> #include "DXUtil.h" #include "D3DEnumeration.h" #include "D3DSettings.h" #include "D3DApp.h" #include "D3DFont.h" #include "D3DFile.h" #include "D3DUtil.h" int g_iNumTiles = 2; // Формат вершин для трехмерных блоков struct D3DVERTEX { D3DXVECTOR3 p; D3DXVECTOR3 n; FLOAT tu, tv; static const DWORD FVF; }; const DWORD D3DVERTEX::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; class CD3DFramework : public CD3DApplication { CD3DFont* m_pStatsFont; TCHAR m_strFont[LF_FACESIZE]; DWORD m_dwFontSize; // Данные трехмерных объектов CD3DMesh* m_pObject[32]; // Массив целых чисел для хранения блочной карты int m_iTileMap[100]; short m_shTileMapWidth; short m_shTileMapHeight; // Размеры окна short m_shWindowWidth; short m_shWindowHeight; protected: HRESULT OneTimeSceneInit(); HRESULT InitDeviceObjects(); HRESULT RestoreDeviceObjects(); HRESULT InvalidateDeviceObjects(); HRESULT DeleteDeviceObjects(); HRESULT Render(); HRESULT FrameMove(); HRESULT FinalCleanup(); HRESULT CreateD3DXTextMesh(LPD3DXMESH* ppMesh, TCHAR* pstrFont, DWORD dwSize); public: LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); CD3DFramework(); };

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

ПРИМЕЧАНИЕ Вспомогательные файлы, такие как d3dfile.cpp, d3dapp.cpp, d3dsettings.cpp, и т.д., находятся в той папке, куда вы установили DirectX SDK. Если вы не меняли предлагаемый путь по умолчанию, файлы находятся в папке C:\DXSDK\Samples\C++\Common.

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

Следующее изменение находится в структуре данных D3DVERTEX. Ее формат слегка отличается от использованного ранее. Это сделано для поддержки формата вершин трехмерных моделей. Для такой поддержки необходима переменная FVF типа DWORD. Это единственное отличие от использованного ранее формата вершин.

Спустимся ниже к определению класса. Здесь добавлена новая переменная с именем m_pObject. Это массив значений типа CD3DMesh. Объект CD3DMesh предоставляется библиотекой d3dfile.cpp. Это ваше окно в мир загрузки и отображения трехмерных моделей. Я произвольным образом установил размер массива равным 32. Это указывает, что максимальное количество загруженных блоков будет равно 32. Не стоит волноваться, — если захотите, вы в дальнейшем всегда сможете изменить это число.




Есть только один заголовочный файл, который представляет для нас интерес — main.h. В этом заголовочном файле я выполняю следующие действия:

  • Объявляю глобальные переменные Direct3D.
  • Описываю пользовательскую структуру формата вершин.
  • Объявляю различные глобальные переменные проекта.
  • Определяю прототипы функций.





Главный заголовочный файл проекта называется main.h. В нем я выполняю следующие действия:

  • Устанавливаю глобальные переменные Direct3D.
  • Устанавливаю структуру настраиваемого формата вершин.
  • Устанавливаю различные глобальные переменные.
  • Определяю прототипы функций.
  • Устанавливаю глобальные данные активных зон.
  • Устанавливаю глобальные данные кнопок мыши.



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




Откройте заголовочный файл main.h и следуйте за мной. Заголовочный файл в этом примере очень простой и короткий. Вот он целиком:

#ifndef MAIN_H #define MAIN_H #define STRICT #include <windows.h> #include <stdio.h> #include <D3DX9.h> #include <dmusici.h> #include <dsound.h> #include <dshow.h> #include <dxutil.h> // Прототипы функций LRESULT WINAPI fnMessageProcessor(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void vCleanup(void); bool bInitializeSoundSystem(HWND hWnd); void vPlaySound(void); // Глобальные звуковые данные IDirectMusicLoader8 *g_pLoader; IDirectMusicPerformance8 *g_pPerformance; IDirectMusicSegment8 *g_pSound; #endif

Список включаемых файлов не должен преподнести вам много сюрпризов. В основном это обычные включаемые файлы для Windows-программы. Единственный файл, добавляемый специально для DirectMusic — это dmusici.h.

В разделе прототипов функций появились две новые функции: bInitializeSoundSystem() и vPlaySound(). Назначение обоих очевидно из их названий. (Разве вы не любите самодокументируемый код?)

Следующий блок кода заголовочного файла содержит глобальные переменные, которые я использую в программе. Если вы прочитали предыдущий раздел этой главы, они должны выглядеть для вас очень знакомо. Интерфейс g_pLoader используется для загрузки звукового файла, интерфейс g_pPerformance предназначен для воспроизведения звука, а интерфейс g_pSound содержит загружаемые из звукового файла данные.

ПРИМЕЧАНИЕ Я вовсе не поощряю вас использовать глобальные переменные в коде. Я применяю их в примерах только для того, чтобы сделать код как можно проще.


Заголовочный файл main.h содержит обычный набор объявлений глобальных переменных и директив включения файлов, необходимых для примера. Вот как выглядит код секции с директивами включения файлов:

#include <windows.h> #include <stdio.h> #include <D3DX9.h> #include <dxutil.h> #include <dshow.h>

Новым в этом блоке является включение файла dshow.h. Он необходим для вызова интерфейсов и функций DirectShow. Если вы планируете использовать функциональность DirectShow, убедитесь, что этот файл есть в списке включаемых.

В следующем блоке кода находятся прототипы функций. Вот как он выглядит:

LRESULT WINAPI fnMessageProcessor(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void vCleanup(void); bool bPlayTitleMusic(void); void vStopTitleMusic(void); void vCheckMusicStatus(void);

Функция fnMessageProcessor() — это обычный обработчик сообщений Windows. Здесь нет ничего нового — все та же старая чепуха.

Функция vCleanup() вызывается перед выходом из программы. Она выполняет освобождение интерфейсов.

Функция bPlayTitleMusic() вызывается один раз в начале программы. Она инициализирует DirectShow, загружает файл MP3 и начинает его воспроизведение.

Функция vStopTitleMusic() останавливает воспроизведение музыки перед завершением работы программы.

Функция vCheckMusicStatus() проверяет не завершилось ли воспроизведенеи музыкального сегмента. Если да, воспроизведение музыки повторяется с начала.

Далее в заголовочном файле расположены глобальные переменные. Я создаю несколько указателей на интерфейсы и одну логическую переменную, как показано ниже:

bool g_bBackgroundMusicActive = 0; IGraphBuilder *g_pGraph; IMediaControl *g_pMediaControl; IMediaEvent *g_pEvent; IMediaSeeking *g_pSeeking;

Переменная g_bBackgroundMusicActive используется для отслеживания состояния музыки. Если музыка воспроизводится, ее значение равно 1. Если нет, значение равно 0.

Переменная g_pGraph является указателем на интерфейс IGraphBuilder. Эй, эй, что это за граф?



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