DirectX 9 Graphics. Анимированные спрайты
Язык программирования: С++Платформа: Win32
Обрати внимание
В литературе по DirectX Graphics и в исходных кодах примеров можно встретить множество отсылок именно к Direct3D. Часто пишут Direct3D, подразумевая его более современный аналог DirectX Graphics. И наоборот. Таким образом часто (но не всегда) эти два названия синонимичны.
Т.к. наш сайт посвящён созданию компьютерных игр, ряд функций будут созданы "с прицелом" на дальнейшую разработку игрового движка.
Содержание
- DirectX 9 Graphics. Анимированные спрайты
- Intro
- Техника отрисовки анимированных спрайтов средствами Direct3D
- Загружаем изображение спрайта (Loading the Sprite Image)
- Создаём объект текстуры
- Получаем размеры файла изображения. Функция D3DXGetImageInfoFromFile
- Загружаем изображение спрайта из файла растрового изображения. Функция D3DXCreateTextureFromFileEx
- (Опционально) объединяем вышеперечисленные фрагменты кода в одну авторскую функцию-обёртку (wrapper-function) LoadTexture
- Создаём объект ID3DXSprite
- Вызываем метод Begin
- Вызываем метод SetTransform
- Вызываем метод Draw
- Вызываем метод End
- Загружаем изображение спрайта (Loading the Sprite Image)
- Пример приложения, выводящего на экран анимированныи спрайт
- Создаём Проект приложения D3D9ASprite01
- Добавляем в Проект WinMain.cpp
- Добавляем в Проект заголовочный файл dxfunc.h
- Добавляем в Проект файл исходного кода dxfunc.cpp
- Добавляем в Проект заголовочный файл Game.h
- Добавляем в Проект файл исходного кода Game.cpp
- Готовим Проект D3D9ASprite01 к компиляции
- Выбираем многобайтовую кодировку
- Отключаем инкрементную компоновку (incremental linking)
- Удаляем файл cvtres.exe
- Отключаем использование компоновщиком библиотеки libci.dll
- Указываем пути к DirectX SDK 9
- Указываем пути к Windows SDK
- Прописываем библиотеки d3d9.lib, d3dx9.lib и WinMM.LIB в окне "Дополнительные зависимости" (Additional dependencies) компоновщика (Linker)
- Компилируем Проект D3D9ASprite01
- Работа над статьёй приостановлена
- Источники
Intro
В этой статье мы научимся создавать и применять 2D-спрайты, которые широко применяются при создании средствами Direct3D.1 Спрайты представляют собой маленькие растры (bitmaps; часто с альфаканалом прозрачности), которые выводятся на экран и обозначают определённые игровые объекты (например космический корабль или фигурку игрока/противника в 2D-платформере). Все 2D-игры используют спрайты наряду с т.н. тайлами (англ. "tiles" - плитки). Тайлы применяются для заполнения фона игровой сцены в большинстве 2D-игр. Статья также расскажет о том, как контролировать анимацию спрайта (если есть) и как перемещать спрайт по экрану. С точки зрения Direct3D 9 (и выше) спрайт представляет собой прямоугольный 3D-объект с текстурой, нанесённой на прямоугольник (состоящий из двух треугольников с одной общей стороной).Техника отрисовки анимированных спрайтов средствами Direct3D
Существует 2 способа вывода спрайтов средствами Direct3D. Оба они предполагают отслеживание положения (позиции) спрайта, его размера, скорости и других свойств.Первый способ - простой. Загружаем изображение спрайта в D3D-поверхность (surface) и выводим путём вызова функции StretchRect.
Второй способ сложнее, но более продвинутый. Применяем специальный класс D3DXSprite, который специально создан для работы со спрайтами. Для хранения изображений спрайта D3DXSprite использует текстуры вместо поверхностей. Это часто бывает полезно при создании различных экранных виджетов (= панелей управления), которые встречаются в большинстве игр.2 В любом случае загрузка изображения в текстуру не сложнее загрузки оного в поверхность.
Воспользуемся вторым способом и создадим Проект приложения, выводящего на экран анимированный спрайт.
Для отрисовки текстуры на 2D-пространстве экрана в главном цикле рендеринга приложения вызывают методы класса D3DXSprite. Но обо всём по порядку.
Загружаем изображение спрайта (Loading the Sprite Image)
В стародавние времена процедуры-блиттеры для 2D-спрайта писали на "голом" ассемблере. Теперь всё это выполняют встроенные методы Direct3D.Первое, на что нужно обратить внимание при использовании D3DXSPRITE, это то, что данный интерфейс для отрисовки спрайта применяет текстуру, а не поверхность. Поэтому здесь самым "ходовым" объектом будет LPDIRECT3DTEXTURE9. Технически это также быстро, как и рендеринг с помощью поверхностей (при использовании аппаратного ускорения).
Создаём объект текстуры
Объявим объект текстуры, в который позднее загрузим изображение спрайта:LPDIRECT3DTEXTURE9 texture = NULL;
Получаем размеры файла изображения. Функция D3DXGetImageInfoFromFile
D3DXIMAGE_INFO info; result = D3DXGetImageInfoFromFile("image.bmp", &info);
Предполагается, что растровый файл изображения расположен в одном каталоге с исполняемым файлом приложения.
При наличии файла с картинкой, в (заранее созданную) структуру info буду записаны ширина (width) и высота (height) изображения в пикселах. Эти данные необходимы для следующего шага.
Загружаем изображение спрайта из файла растрового изображения. Функция D3DXCreateTextureFromFileEx
Загружаем изображение из файла прямо в объект текстуры с помощью функции D3DXCreateTextureFromFileEx. Вот её прототип (DirectX 9):HRESULT WINAPI D3DXCreateTextureFromFileEx( LPDIRECT3DDEVICE9 pDevice, LPCSTR pSrcFile, UINT Width, UINT Height, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, DWORD Filter, DWORD MipFilter, D3DCOLOR ColorKey, D3DXIMAGE_INFO *pSrcInfo, PALETTEENTRY *pPalette, LPDIRECT3DTEXTURE9 *ppTexture );
Выглядит внушительно. На деле большинство её параметров выставляются по умолчанию либо в NULL.
(Опционально) объединяем вышеперечисленные фрагменты кода в одну авторскую функцию-обёртку (wrapper-function) LoadTexture
Функция LoadTexture выполняет все шаги по подготовке к загрузке текстуры из файла + непосредственно производит загрузку:LPDIRECT3DTEXTURE9 LoadTexture(char *filename, D3DCOLOR transcolor) { // Указатель на объект текстуры LPDIRECT3DTEXTURE9 texture = NULL; // Структура для хранения информации о файле изображения D3DXIMAGE_INFO info; // Стандартное Windows-значение, возвращаемое функцией HRESULT result; // Получаем ширину (width) и высоту (height) изображения из загружаемого файла result = D3DXGetImageInfoFromFile(filename, &info); if(result != D3D_OK) return NULL; // Создаём новую текстуру путём загрузки битмапа (=файла растрового изображения) D3DCreateTextureFromFileEx( d3ddev, // Объект устройства Direct3D filename, // Имя файла ращстрового изображения info.Width, // Ширина растрового изображения info.Height, // Высота растрового изображения 1, // Число мип-мэп уровней (mip-map levels; 1 - значит без цепочек) D3DPOOL_DEFAULT, // Тип поверхности (стандартная) D3DFMT_UNKNOWN, // Формат цветности поверхности (D3DFMT_UNKNOWN = формат по умолчанию) D3DPOOL_DEFAULT, // Пул памяти для текстуры D3DX_DEFAULT, // Фильтр изображения D3DX_DEFAULT, // Мип-фильтр изображения transcolor, // Ключевой цвет прозрачности &info, // Структура с информацией о загруженном файле изобаржения NULL, // Цветовая палитра &texture // Результирующий объект текстуры ); // Проверяем, что изображение загружено успешно if(result != D3D_OK) return NULL; return texture; }
Создаём объект ID3DXSprite
- Представляет собой специальный дескриптор (handler), содержащий функции отрисовки спрайта из файла-текстуры (с применением различных трансформаций).
- Объявляется, например, так:
LPD3DXSPRITE sprite_handler;
Далее созданный объект применяется путём вызова функции D3DXCreateSprite, которая "присоединяет" дескриптор спрайта к основному объекту устройства Direct3D и его устройству, давая знать, с какими параметрами следует отрисовывать спрайты в бэкбуфер. Вот её прототип:
HRESULT WINAPI D3DXCreateSprite(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE *ppSprite);
Вот пример её применения:
result = D3DXCreateSprite(d3ddev, &sprite_handler);
Применение объекта ID3DXSprite позволяет изменять спрайт различными способами а также отрисовывать его с использованием аппаратного 3D-ускорения (если есть). Спрайты с прозрачностью также легко отрисовываются путём указания альфа-цвета (он же альфа-канал, канал прозрачности) у изображения-источника. Чёрный (0,0,0) наиболее часто используется для цвета прозрачности. Иногда также использую розовый цвет (255,0,255) т.к. он редко применяется в самих изображениях.
Вызываем метод Begin
- Экспонирован интерфейсом ID3DXSprite (DirectX 9). Он готовит созданный выше объект ID3DXSprite к отрисовке текстуры на экране:
HRESULT Begin(DWORD Flags);
В его единственном параметре передаются флаги (хранятся в d3dx9core.h), но чаще ставят 0. Флагов может быть несколько (объединяются оператором логического "и" &&). Вот их описание:3
ФЛАГ | ОПИСАНИЕ |
---|---|
D3DXSPRITE_DONOTSAVESTATE | Текущее состояние объекта устройства Direct3D не сохраняется и не восстанавливается при вызове методов Begin и End. |
D3DXSPRITE_DONOTMODIFY_RENDERSTATE | При вызове метода Begin рендерстейт (render state) объекта устройства Direct3D не изменяется. |
D3DXSPRITE_OBJECTSPACE | Трансформации мира, вида и проекции не изменяют спрайты. |
D3DXSPRITE_BILLBOARD | Каждый спрайт будет вращаться вокруг своего центра, оставаясь всё время повернутым к вьюеру (= виртуальной камере). Перед указанием данного флага необходимо сначала вызвать функции SetWorldViewLH (для леворучной картезианской системы координат) или SetWorldViewRH (для праворучной картезианской системы координат). |
D3DXSPRITE_ALPHABLEND | Перед указанием данного флага необходимо сначала активировать альфа-смешивание (alpha blending) путём вызова функции SetRenderState c флагом D3DRS_ALPHATESTENABLE выставленным в TRUE (только в случае ненулевого альфа-канала). Подробнее об этом здесь: Alpha Blending State (Direct3D 9). |
D3DXSPRITE_SORT_TEXTURE | Сортировать спрайты по размерам их текстур. Это может повысить производительность в случае неперекрывающихся (non-overlapped) спрайтов. Данный флаг можно комбинировать с флагами D3DXSPRITE_SORT_DEPTH_FRONTTOBACK или D3DXSPRITE_SORT_DEPTH_BACKTOFRONT. Это даст сортировку списка спрайтов сперва по глубине (= увеличению Z-координаты), а затем по текстуре. |
D3DXSPRITE_SORT_DEPTH_FRONTTOBACK | Спрайты перед рендерингом сортируются по глубине (= увеличению Z-координаты), начиная с самых ближних и заканчивая самыми дальними (от вьюера). |
D3DXSPRITE_SORT_DEPTH_BACKTOFRONT | Спрайты перед рендерингом сортируются по глубине (= увеличению Z-координаты), начиная с самых дальних и заканчивая самыми ближними (к вьюеру). |
D3DXSPRITE_DO_NOT_ADDREF_TEXTURE | Отключаем вызов функции AddRef (добавляет ссылку) в каждом кадре. Отключаем вызов функции Release при каждом вызове функции Flush. Повышает производительность. |
Вызываем метод SetTransform
- Экспонирован интерфейсом ID3DXSprite (DirectX 9).
HRESULT SetTransform(const D3DXMATRIX *pTransform);
В качестве единственного вводного параметра указывается матрица 2D-преобразований текстуры спрайта. То есть она (матрица) указывает инстансу ID3DXSprite каким образом наносить на спрайт указанную текстуру. Мы можем транслировать (= переместить) в точку (5,5) от начала координат. Можем даже её повернуть и изменить размеры.
Примечание
Если прописать в коде изменение матрицы 2D-преобразований текстуры спрайта в каждом кадре можно реализовать в игре оч. крутые фишки вроде текущей реки, плывущих по небу облаков и т.д.
Для создания матрицы 2D-преобразований в Direct3D есть специальная функция D3DXMatrixTransformation2D. Вот её прототип:
D3DXMATRIX *WINAPI D3DXMatrixTransformation2D ( D3DXMATRIX *pOut, // Матрица-результат CONST D3DXVECTOR2 *pScalingCenter, // Центр, относительно которого масштабируется текстура FLOAT *pScalingRotation, // Указатель на фактор масштабирования при вращении (scaling rotation factor). // Если масштабирование не нужно, ставим здесь NULL. CONST D3DXVECTOR2 *pScaling, // Указатель на фактор масштабирования (scaling factor). // Если масштабирование не нужно, ставим здесь NULL. CONST D3DXVECTOR2 *pRotationCenter, // 2D-координаты точки центра вращения. // Если вращение не нужно, ставим здесь NULL. FLOAT Rotation, // Угол поворота в радианах. Если вращение не нужно, ставим здесь 0. CONST D3DXVECTOR2 *pTranslation // Смещение текстуры по обеим осям относительно начала координат. // Если смещение не нужно, ставим здесь NULL. );
Сразу после построения 2D-матрицы преобразований текстуры, её можно смело передавать в функцию SetTransform:
D3DXMatrixTransformation2D(&Mat, NULL, 0, NULL, NULL, 0, NULL); Sprite->SetTransform(&Mat);
Вызываем метод Draw
- Экспонирован интерфейсом ID3DXSprite (DirectX 9).
- Выводит текстурированный спрайт на экран.
HRESULT Draw ( LPDIRECT3DTEXTURE9 pTexture, // Указатель на текстуру CONST Rect *pSrcRect, // Указатель на прямоугольник, на котором будет отрисована текстура. Можно выставить в NULL. CONST D3DXVECTOR3 *pCenter, // Точка центра спрайта. Можно выставить в NULL. CONST D3DXVECTOR3 *pPosition, // Вектор трансляции спрайта (в случае его перемещения). Можно выставить в NULL. D3DCOLOR Color // Можно окрасить текстуру (придать цветовой оттенок) либо изменить значение её альфа-канала. );
В третьем и четвёртом параметрах также можно указать смещение и вращение (теперь уже спрайта). Если это не нужно, просто выставляем здесь NULL.
Вызываем метод End
- Экспонирован интерфейсом ID3DXSprite (DirectX 9).
- Указывает на завершение рендеринга спрайта.
- Не требует аргументов:
Sprite->End();
Пример приложения, выводящего на экран анимированныи спрайт
Создадим Проект приложения, демонстрирующий работу со спрайтами с применением объекта D3DXSPRITE. За основу возьмём исходный код Проекта из статьи DirectX 9 Graphics. Поверхности и растры (финальный вариант Проекта D3D9Surface01 в конце статьи), который, в свою очередь, основан на исходном коде базового приложения Windows из статьи Создание приложений Сpp Win32. Мы продолжим разносить код в отдельные файлы, увеличив степень его модульности. Будут созданы отдельные пары файлов .cpp и .h для Windows-функций, DirectX-функций и функций самой игры. Хорошо структурированный код - отличная основа будущего игрового движка.Перед началом проверь, что у тебя установлены следующие программные компоненты:
- MS Visual C++ 2010;
- DirectX SDK 9
- Windows SDK (для программирования под Win7/8/10).
- + инструкции по их установке ты найдёшь в разделе "Софт" нашего сайта;
- Бесплатны;
- Без труда гуглятся.
Создаём Проект приложения D3D9ASprite01
- Создай пустой Проект с именем D3D9ASprite01.
Добавляем в Проект WinMain.cpp
Для чистоты эксперимента мы создали пустой Проект, т.е. без каких-либо файлов в нём. Создадим единственный файл с исходным кодом WinMain.cpp.- В "Обозревателе решений" главного окна MSVC++2010 щёлкни правой кнопкой мыши по папке (в терминологии Майкрософт это не папки, а фильтры!) "Файлы исходного кода" Проекта D3D9ASprite01.
- Во всплывающем меню Добавить->Создать элемент...
- В появившемся окне выбери "Файл С++ (.cpp)" и в поле "Имя" введи WinMain.cpp. Жмём "Добавить".
Добавленный файл сразу откроется в правой части MSVC++2010.
- В только что созданном и открытом файле WinMain.cpp набираем следующий код:
// Файл: WinMain.cpp // Описание: Шаблон оконного приложения Windows. Простейшее (базовое) приложение Windows, // выводящее на экран окно. // www.igrocoder.ru 2015 // При использовании просьба указывать ссылку на источник. #define STRICT #define WIN32_LEAN_AND_MEAN // Уменьшаем кол-во используемых компонентов в программе. #include <windows.h> #include "dxfunc.h" #include "Game.h" // Прототип функции WinMain int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow); // Объявление оконной процедуры LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Реализация главной функции программы int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hWnd; // Дескриптор окна MSG msg; // Структура сообщения CoInitialize(NULL); WNDCLASSEX wndClass; // Объявляем экземпляр класса программы на базе WNDCLASSEX // Заполняем структуру оконного класса wndClass.cbSize=sizeof(wndClass); wndClass.style=CS_CLASSDC; // Поочерёдный доступ к контексту устройства (Device Context) wndClass.lpfnWndProc=WindowProc; // Оконная процедура wndClass.cbClsExtra=0; wndClass.cbWndExtra=0; wndClass.hInstance=hInstance; // Экземпляр окна wndClass.hIcon=LoadIcon(NULL, IDI_APPLICATION); // Пиктограмма приложения wndClass.hIconSm=LoadIcon(NULL, IDI_APPLICATION); // Малая пиктограмма приложения wndClass.hCursor=NULL; // Курсор при наведении на окно wndClass.hbrBackground=NULL; // Закрашиваем окно чёрным цветом wndClass.lpszMenuName=NULL; // Дескриптор Главного меню окна. Сейчас оно не нужно wndClass.lpszClassName="GameClass"; // Обзываем оконный класс. // Если класс не зарегистрируется, досрочно прерываем выполнение программы if(!RegisterClassEx(&wndClass)) return FALSE; // Создание окна на основе зарегистрированного класса hWnd=CreateWindow( "GameClass", // Класс окна. "My game title", // Текст заголовка (на верхнем тулбаре). WS_OVERLAPPEDWINDOW, // Обычное окно с кнопками в правом верхнем углу. 0, 0, // Координаты X и Y iWidth, // Ширина окна iHeight, // Высота окна NULL, // Дескриптор родительского окна NULL, // Дескриптор меню hInstance, // Дескриптор экземпляра приложения NULL); // Дополнительные данные if(!hWnd) return(FALSE); // Собственно, показываем окно ShowWindow(hWnd, SW_NORMAL); UpdateWindow(hWnd); // Очищаем структуру сообщения ZeroMemory(&msg, sizeof(MSG)); if(GameInit(hWnd) == TRUE) { while(TRUE) { if(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) { // Есть сообщение! Обработаем его как обычно... TranslateMessage(&msg); DispatchMessage(&msg); if(msg.message == WM_QUIT) break; } else { // Главный цикл игры (mainloop) GameRun(hWnd); } } } CoUninitialize (); //Удаляем регистрацию класса UnregisterClass("GameClass", hInstance); // Выходим из приложения return (msg.wParam); } // Оконная процедура LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: // В случае этого сообщения... GameEnd(hWnd); PostQuitMessage(0); // Говорим Windows закрыть приложение break; // В случае любых других сообщений... default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0; }
- Сохрани Решение (Файл->Сохранить все).
Добавляем в Проект заголовочный файл dxfunc.h
dxfunc.h содержит объявления DirectX-функций, реализованных в dxfunc.cpp. ОК, приступаем.- Убедись, что MSVC++2010 запущена и в ней открыт Проект D3D9ASprite01, созданный выше.
- В "Обозревателе решений" главного окна MSVC++2010 щёлкни правой кнопкой мыши по папке (в терминологии Майкрософт это не папки, а фильтры!) "Заголовочные файлы" Проекта D3D9ASprite01.
- Во всплывающем меню Добавить->Создать элемент...
- В появившемся окне выбери "Заголовочный файл (.h)" и в поле "Имя" введи "dxfunc.h".
- Жмём "Добавить".
- В только что созданном и открытом файле dxfunc.h набираем следующий код:
#ifndef _DXFUNC_H_ #define _DXFUNC_H_ #include <d3d9.h> #include <d3dx9.h> #include <d3dx9math.h> // Прототипы функций HRESULT d3d9Init(IDirect3D9 **d3d, IDirect3DDevice9 **d3ddev, HWND hWnd, DWORD iWidth, DWORD iHeight, BOOL bFullScreen ); LPDIRECT3DSURFACE9 LoadSurface(char *, D3DCOLOR); LPDIRECT3DTEXTURE9 LoadTexture(char *, D3DCOLOR); // Объявления переменных extern LPDIRECT3D9 d3d; extern LPDIRECT3DDEVICE9 d3ddev; extern LPDIRECT3DSURFACE9 backbuffer; #endif
- Сохрани Решение (Файл->Сохранить все).
В этот раз из WinMain.cpp сюда также "переехали" объявления объектов Direct3D. Перед каждым стоит служебное слово "extern", означающее их "открытость" для применения в функциях за пределами dxfunc.h .
Добавляем в Проект файл исходного кода dxfunc.cpp
В dxfunc.cpp содержатся реализации функций, объявленных в dxfunc.h. ОК, приступаем.- Убедись, что MSVC++2010 запущена и вней открыт Проект D3D9ASprite01, созданный выше.
- В "Обозревателе решений" главного окна MSVC++2010 щёлкни правой кнопкой мыши по папке (в терминологии Майкрософт это не папки, а фильтры!) "Файлы исходного кода" Проекта D3D9ASprite01.
- Во всплывающем меню Добавить->Создать элемент...
- В появившемся окне выбери "Файл C++ (.cpp)" и в поле "Имя" введи "dxfunc.cpp".
- Жмём "Добавить".
- В только что созданном и открытом файле dxfunc.cpp набираем следующий код:
// Файл: dxfunc.cpp // Реализация DX-функций, объявленных в dxfunc.h // Сборник DirectX-функций #include "dxfunc.h" // Объявления переменных LPDIRECT3D9 d3d = NULL; LPDIRECT3DDEVICE9 d3ddev = NULL; LPDIRECT3DSURFACE9 backbuffer = NULL; HRESULT d3d9Init(IDirect3D9 **d3d, IDirect3DDevice9 **d3ddev, HWND hWnd, DWORD iWidth, DWORD iHeight, BOOL bFullScreen) { // Инициализируем Direct3D if ((*d3d = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) { return E_FAIL; } // Заполняем основные (общие) параметры представления D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof( d3dpp ) ); d3dpp.BackBufferWidth = iWidth; d3dpp.BackBufferHeight = iHeight; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.hDeviceWindow = hWnd; // Запрос на отображение в полноэкранном режиме int iRes; if (!bFullScreen) { iRes=MessageBox(hWnd, "Перейти в полноэкранный режим?", "Screen", MB_YESNO | MB_ICONQUESTION); } else { iRes = IDYES; } if(iRes == IDYES) { ////////////////////////////////////////////////////////// // Полноэкранный режим ////////////////////////////////////////////////////////// // Установка параметров полноэкранного режима d3dpp.Windowed = FALSE; d3dpp.BackBufferCount = 1; d3dpp.BackBufferFormat = D3DFMT_R5G6B5; d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP; d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; // При значении D3DPRESENT_INTERVAL_DEFAULT Direct3D сам выбирает частоту обновления. // Обычно она равна частоте смены кадров (FPS). d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; } else { // Доп. параметры для оконного режима // Получить формат пикселя D3DDISPLAYMODE d3ddm; (*d3d)->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); // Установка параметров оконного режима d3dpp.Windowed = TRUE; d3dpp.BackBufferFormat = d3ddm.Format; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; } if(FAILED((*d3d)->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, d3ddev))) { return E_FAIL; } // Очищаем бэкбуфер в чёрный цвет (*d3ddev)->Clear(0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); // Создаём указатель на бэкбуфер (*d3ddev)->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); } LPDIRECT3DSURFACE9 LoadSurface(char *filename, D3DCOLOR transcolor) { LPDIRECT3DSURFACE9 image = NULL; D3DXIMAGE_INFO info; HRESULT result; // Получаем из файла длину и высоту изображения D3DXGetImageInfoFromFile(filename, &info); if(result != D3D_OK) return NULL; // Создаём поверхность result = d3ddev->CreateOffscreenPlainSurface( info.Width, // Ширина изображения info.Height, // Высота изображения D3DFMT_X8R8G8B8, // Формат цветности поверхности D3DPOOL_DEFAULT, // Используемый пул памяти &image, // Указатель на поверхность NULL); // Зарезервирован (всегда NULL) if(result != D3D_OK) return NULL; // Загружаем изображение из файла в созданную поверхность result = D3DXLoadSurfaceFromFile( surface, // Поверхность-получатель NULL, // Палитра-получатель NULL, // Прямоугольник-получатель "test.jpg", // Имя файла растрового изображения NULL, // Прямоугольник-источник D3DX_DEFAULT, // Метод фильтрации изображения 0, // Флаг прозрачности (0 - значит без неё) NULL); // Инфо о файле растрового изображения (обычно всегда NULL) // Проверяем, что файл успешо загружен if(result != D3D_OK) return NULL; return image; } LPDIRECT3DTEXTURE9 LoadTexture(char *filename, D3DCOLOR transcolor) { // Указатель на текстуру LPDIRECT3DTEXTURE9 texture = NULL; // Структура, куда сохраним инфу о файле растрового изображения (=битмапе) D3DXIMAGE_INFO info; // Стандартное значение, возвразаемое в ОС Windows HRESULT result; // Получаем ширину и высоту изображения из битмапа result = D3DXGetImageInfoFromFile(filename, &info); if(result != D3D_OK) return NULL; // Создаём текстуру путём загрузки битмапа D3DXCreateTextureFromFileEx( d3ddev, // Объект устройства Direct3D filename, // Имя файла битмапа info.Width, // Ширина битмапа info.Height, // Высота битмапа 1, // Кол-во мипмап-уровней (1 - значит без цепочки) D3DPOOL_DEFAULT, // Тип поверхности (стандартная) D3DFMT_UNKNOWN, // Формат цветности поверхности (по умолчанию) D3DPOOL_DEFAULT, // Пул памяти для текстуры D3DX_DEFAULT, // Фильтр изображения D3DX_DEFAULT, // Мип-фильтр transcolor, // Ключевой цвет для прозрачности &info, // Инфо о битмапе (загружено выше из файла битмапа) NULL, // Цветовая палитра &texture ); // Указатель на конечный объект текстуры // Проверяем, что битмап успешно загружен if(result != D3D_OK) return NULL; return texture; }
- Сохрани Решение (Файл->Сохранить все).
Добавляем в Проект заголовочный файл Game.h
Game.h содержит объявления DirectX-функций, реализованных в Game.cpp (его создадим ниже).ОК, приступаем.
- Убедись, что MSVC++2010 запущена и в ней открыт Проект D3D9ASprite01, созданный выше.
- В "Обозревателе решений" главного окна MSVC++2010 щёлкни правой кнопкой мыши по папке (в терминологии Майкрософт это не папки, а фильтры!) "Заголовочные файлы" Проекта D3D9ASprite01.
- Во всплывающем меню Добавить->Создать элемент...
- В появившемся окне выбери "Заголовочный файл (.h)" и в поле "Имя" введи "Game.h".
- Жмём "Добавить".
- В только что созданном и открытом файле Game.h набираем следующий код:
// Файл: Game.h // Объявления функций, специфичных для игры, реализации которых // размещены в Game.cpp #ifndef _GAME_H_ #define _GAME_H_ #include "dxfunc.h" // Для инициализации Direct3D + подключения d3d9.h #include <time.h> // Для инициализации таймера #include <stdio.h> #include <stdlib.h> // Заголовок приложения (выводится на тулбаре окна) #define APPTITLE "Animated Sprite Test" // Настройки видеорежима #define FULLSCREEN 1 #define iWidth 640 #define iHeight 480 // Макрос асинхронного считывания нажатий клавиатуры #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1:0) #define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1:0) // Прототипы игровых функций bool GameInit(HWND); // Инициализирует игру. void GameRun(HWND); void GameEnd(HWND); // Структура для хранения информации о спрайте typedef struct { int x,y; int width, height; int movex, movey; int curframe, lastframe; int animdelay, animcount; } SPRITE; #endif
- Сохрани Решение (Файл->Сохранить все).
Добавляем в Проект файл исходного кода Game.cpp
В Game.cpp содержатся реализации функций, объявленных в Game.h. ОК, приступаем.- Убедись, что MSVC++2010 запущена и вней открыт Проект D3D9ASprite01, созданный выше.
- В "Обозревателе решений" главного окна MSVC++2010 щёлкни правой кнопкой мыши по папке (в терминологии Майкрософт это не папки, а фильтры!) "Файлы исходного кода" Проекта D3D9ASprite01.
- Во всплывающем меню Добавить->Создать элемент...
- В появившемся окне выбери "Файл C++ (.cpp)" и в поле "Имя" введи "Game.cpp".
- Жмём "Добавить".
- В только что созданном и открытом файле Game.cpp набираем следующий код:
// Файл: Game.cpp // Реализация функций, специфичных для игры, объявленных в Game.h #include "Game.h" LPDIRECT3DTEXTURE9 test_image[7]; SPRITE TestSprite; LPDIRECT3DSURFACE9 back; LPD3DXSPRITE SpriteHandler; HRESULT result; // Переменные таймера long start = GetTickCount(); // Инициализация игры bool GameInit(HWND hWnd) { char s[20]; int n; // Устанавливаем генератор случайных чисел // на основе текущего времени srand(time(NULL)); MessageBox(hWnd, "Сейчас будем создавать дескриптор спрайта", "Note", MB_OK); // Создаём объект дескриптора спрайта result = D3DXCreateSprite(d3ddev, &SpriteHandler); if(result != D3D_OK) { MessageBox(hWnd, "Спрайт не создан(", "Note", MB_OK); return NULL; } // Загружаем анимацию спрайта for(n=0; n<6; n++) { // Приводим имя файла к нужному виду sprintf(s,"test%d.jpg",n+1); // Загружаем текстуру с розовым цветом прозрачности test_image[n] = LoadTexture(s, D3DCOLOR_XRGB(255, 0, 255)); if(test_image[n] == NULL) return NULL; } // Загружаем фоновое изображение back = LoadSurface("background.bmp", NULL); // Инициализируем свойства спрайта TestSprite.x = 100; TestSprite.y = 150; TestSprite.width = 96; TestSprite.height = 96; TestSprite.curframe = 0; TestSprite.lastframe = 5; TestSprite.animdelay = 2; TestSprite.animcount = 0; TestSprite.movex = 8; TestSprite.movey = 0; // Возвращаем ОК return 1; } // Главный цикл игрового приложения void GameRun(HWND hWnd) { // Проверяем корректность созданного объекта устройства Direct3D if(d3ddev == NULL) return; // Очищаем бэкбуфер в синий цвет. d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0); // Готов ли следующий кадр? // Поддерживает заданную частоту кадров (framerate) в приложении? if(GetTickCount() - start >= 30) { // Сбрасываем таймер в 0 start = GetTickCount(); // Перемещаем спрайт TestSprite.x += TestSprite.movex; TestSprite.y += TestSprite.movey; // При приближении спрайта к краям окна "переносим" его // на противоположную сторону if(TestSprite.x > iWidth - TestSprite.width) { TestSprite.x=0; } if(TestSprite.x < 0) { TestSprite.x = iWidth - TestSprite.width; } // В случае достижения паузы в анимации определённой величины... if(++TestSprite.animcount > TestSprite.animdelay) { // Обнуляем счётчик кадров TestSprite.animcount = 0; // Анимируем спрайт if(++TestSprite.curframe > TestSprite.lastframe) { TestSprite.curframe = 0; } } } // Начинаем рендеринг if(d3ddev->BeginScene() ) { // Очищаем текущий фон (background) d3ddev->StretchRect(back, NULL, backbuffer, NULL, D3DTEXF_NONE); // Начинаем отрисовку спрайта через его дескриптор SpriteHandler->Begin(D3DXSPRITE_ALPHABLEND); // Создаём вектор для обновления положения спрайта на экране D3DXVECTOR3 position((float)TestSprite.x, (float)TestSprite.y, 0); // Рисуем спрайт SpriteHandler->Draw( test_image[TestSprite.curframe], NULL, NULL, &position, D3DCOLOR_XRGB(255, 255, 255) ); // Заканчиваем отрисовку спрайта через его дескриптор SpriteHandler->End(); // Завершаем рендеринг d3ddev->EndScene(); } // Выводим содержимое бэкбуфера на экран d3ddev->Present(NULL, NULL, NULL, NULL); // При нажатии Esc завершаем работу приложения if(KEY_DOWN(VK_ESCAPE)) { PostMessage(hWnd, WM_DESTROY, 0, 0); } } // Освобождаем память, стирая ранее выделененые ресурсы void GameEnd(HWND hWnd) { int n; // Удаляем поверхность for(n=0; n<6; n++) { if(test_image[n] != NULL) { test_image[n]->Release (); } } if(back != NULL) { back->Release(); } if(SpriteHandler != NULL) { SpriteHandler->Release(); } // Освобождаем ресурсы, выделенные ранее под объект устройства Direct3D. if(d3ddev != NULL) d3ddev->Release(); // Освобождаем ресурсы, выделенные ранее под объект (инстанс) класса IDirect3D9. if(d3d != NULL) d3d->Release(); }
- Сохрани Решение (Файл->Сохранить все). Так-то всё. Осталось скомпилировать Проект, подготовить спрайт и фоновое изображение.
Готовим Проект D3D9ASprite01 к компиляции
Выбираем многобайтовую кодировку
Примечание
В MS Visual C++ 2010 в настройках по умолчанию стоит набор (кодировка) символов UNICODE. В MS Visual C++ 6.0 - напротив, по умолчанию стоит кодировка ANSI (многобайтовая). Данная настройка сильно влияет на типы используемых переменных, что приводит к заметным различиям в исходном коде.
Несмотря на то, что во всех случаях рекомендуется использовать кодировку UNICODE, поддерживаемую во всех современных ОС семейства MS Windows (начиная с Win 2000/XP), большинство книг по программированию игр на классическом C++ придерживаются именно многобайтовой кодировки. Чтобы сильно не переделывать исходные коды под UNICODE, данный Проект мы настроим под многобайтовую кодировку.
Чтобы сильно не переделывать исходные коды под UNICODE, все наши игровые Проекты мы настроим под многобайтовую кодировку. Для этого...
- Убедись, что MSVC++2010 запущена и в ней открыт наш текущий Проект D3D9ASprite01.
- В Обозревателе решений щёлкаем правой кнопкой мыши по названию Проекта D3D9ASprite01.
- Во всплывающем контекстном меню выбираем "Свойства".
- В появившемся окне установки свойств Проекта жмём Свойства конфигурации->Общие, в правой части в строке "Набор символов" выставляем значение "Использовать многобайтовую кодировку".
- Жмём ОК.
- Сохрани Решение (Файл->Сохранить все)
Отключаем инкрементную компоновку (incremental linking)
Инкрементная компоновка призвана сократить время компилирования. Но на деле её присутствие часто вызывает ошибки вроде этой:Error LNK1123: сбой при преобразовании в COFF: файл недопустим или поврежден
Ошибка LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt
В MS Visual C++ 2010 даже компиляция консольных приложений нередко завершается неудачей, а вместо исполняемого файла программист видит сообщение:
LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt.
ПРИЧИНА: MS Visual С++ 2010 "не нравится" версия .NET Framework, установленная в операционной системе. В общих чертах, MS Visual С++ 2010 спрограммирована для работы под управлением .NET Framework 4.0 и сильно к нему привязана. Если точнее, к нему сильно привязана система инкрементной компоновки приложений (incremental linking), которая по умолчанию включена для всех создаваемых проектов.
Во время установки MS Visual C++ 2010 пытается установить свой "родной" .NET Framework 4.0, проверяя версию этой программной платформы, установленную в ОС на данный момент. Если версия .NET Framework ниже 4.0, то она обновляется до 4.0 и всё прекрасно компилируется. Если версия .NET Framework выше 4.0, то всё оставляется как есть: IDE успешно завершает установку, но при компиляции ВСЕХ приложений выскакивает данная ошибка. Более того, ошибка была замечена даже при наличии в системе .NET Framework версии 4.0, но отличающейся от "родной" припиской вроде "Beta" или "Release Candidate".
ВАРИАНТЫ РЕШЕНИЙ:
1. Отключить инкрементную линковку в опциях Проекта.
В главном меню MSVC++2010 выбираем: Проект->Свойства->Свойства конфигурации->Компоновщик(Linker)->Включить инкрементное построение (Incremental Linking). Данный пункт по умолчанию включен для всех новых проектов. Выставляем его в Нет (No). И жмём OK. Инкрементное построение заметно сокращает время компилирования больших проектов. Но в нашем случае его отсутствие некритично.
2. Удалить (переместить в другое место) утилиту cvtres.exe из каталога bin установленной MS Visual C++ 2010.
В нашем случае (Win7 x64) полный путь до данного файла такой: C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\cvtres.exe . Официальное название данного приложения - Microsoft® Resource File To COFF Object Conversion Utility (утилита конвертации файлов двоичных ресурсов в Component Object File Format). Опытным путём установлено, что при линковке IDE "спотыкается" именно об него.
3. Удалить из системы все версии .NET Framework (включая языковые пакеты и всякие профайлеры, если есть) и саму MS Visual C++ 2010.
Всё вышеперечисленное можно без труда найти в меню "Программы и компоненты" (MS Windows Vista/7/8). Затем заново установить MS Visual C++ 2010. При этом автоматом установится .NET Framework 4.0, идущий с ней в наборе.
Третий пункт - самый долгий. На деле почти всегда хватает выполнения первых двух. Данным вопросом озадачивались ребята здесь: https://www.cyberforum.ru/cpp-beginners/thread637174.html?ysclid=l3akpmanrq. После этого линковка (=компоновка) проходит идеально. Подобные "костыли" в IDE от Майков - не редкость. Можно предположить, что команда с головой ударилась в тестирование .NET-возможностей MSVC++2010, совсем забыв о Win32-направлении (либо признав его бесперспективным).
Отключим инкрементную компоновку в свойствах открытого Проекта. Для MS Visual C++ 2010 порядок следующий:
- Убедись, что MSVC++2010 запущена и в ней открыт Проект, с которым работаешь.
- В Обозревателе решений щёлкаем правой кнопкой мыши по названию Проекта.
- Во всплывающем контекстном меню выбираем "Свойства".
- В появившемся окне установки свойств Проекта жмём Свойства конфигурации -> Компоновщик -> Общие (Configuration Properties -> Linker -> General), в правой части в строке "Включить инкрементную компоновку" ставим значение Нет (/INCREMENTAL:NO).
- Жмём ОК.
Удаляем файл cvtres.exe
В нашем случае (Win7 x64) полный путь до данного файла такой: C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\cvtres.exeВ Win32-кодинге он особо ни на что не влияет. Зато без него линковка идёт как по маслу.
Отключаем использование компоновщиком библиотеки libci.dll
Да, даже на данном этапе компиляция Проекта выдаст ошибку. Библиотека libci.dll использовалась в VisualStudio когда-то очень давно, и в современных версях IDE её нет. Тем не менее компоновщик почти всегда вызывает её при компиляции, ругаясь на её отсутствие. Самый простой способ это исправить - запретить использовать libci.dll по умолчанию.ОК, начнём.
- Убедись, что MSVC++2010 запущена и в ней открыт Проект, с которым работаешь в данный момент.
- В Главном меню MS Visual C++ 2010 выбираем Проект -> Свойства (Project -> Properties).
- В появившемся окне установки свойств Проекта последовательно щёлкаем по раскрывающимся ветвям иерархического дерева: Свойства конфигурации -> Компоновщик -> Командная строка (Configuration Properties -> Linker -> Command Promt).
- Пишем в него строку: /NODEFAULTLIB:libci
- Жмём ОК.
- Сохрани Решение (Файл->Сохранить все).
Указываем пути к DirectX SDK 9
Если попытаться скомпилировать Проект D3D9Surface01 в таком виде, то ничего не выйдет.В dxfunc.h можно увидеть директиву включения (#include) заголовочного файла d3d9.h:
... #include <d3d9.h> ...
На данном этапе MSVC++2010 ничего не знает об их местоположении. В статье MS Visual Cpp 2010 Express. Установка и указание путей к DirectX SDK мы указывали пути к DirectX SDK (версии 9 и выше). Здесь всё делается аналогично. Начнём.
- Убедись, что MSVC++2010 запущена и в ней открыт наш текущий Проект D3D9ASprite01.
- Убедись, что DirectX SDK 9 установлен на компьютере и ты уверенно можешь назвать полный путь к его каталогу.
- Жмём правой кнопкой мыши по названию Проекта D3D9ASprite01. Во всплывающем меню выбираем пункт "Свойства".
Или в Главном меню выбираем Проект->Свойства. Или нажимаем Alt+F7.
В появившемся меню свойств проекта выбираем Свойства конфигурации -> Каталоги VC++. В правой части этой страницы расположены пути ко всевозможным каталогам. Здесь нас интересуют только 2 строки: Каталоги включения и Каталоги библиотек.
Указываем каталог включений (include) DirectX SDK 9
- В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги включения. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
В появившемся меню "Каталоги включения" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к заголовочным файлам DirectX SDK 9 (include). В нашем случае это C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
- Жмём "ОК".
Указываем каталог библиотек (lib) DirectX SDK 9
- В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги библиотек. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
- В появившемся меню "Каталоги библиотек" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к 32-разрядным версиям файлов библиотек DirectX SDK 9 (lib). В нашем случае это C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
- Жмём "ОК".
- На Странице свойств тоже жмём "ОК".
- Сохрани Решение (File -> Save All).
Указываем пути к Windows SDK
Помимо указания путей к заголовкам (include) и библиотекам (lib) DirectX SDK, для любого DirectX-Проекта также необходимо указать пути к заголовкам (include) и библиотекам (lib) Windows SDK. Самое смешное, что в MS Visual C++ 2010 эти пути указываются по умолчанию для каждого создаваемого Проекта. В этом нетрудно убедиться, если ещё раз открыть Проект -> Свойства -> Свойства конфигурации - >Каталоги VC++ -> Каталоги включения -> Изменить. В окне "Каталоги включения" в нижней (недоступной для редактирования) части видим список "Унаследованные значения", где в третьей строке стоит значение:$(WindowsSdkDir)include
В результате видим, что добавленные пути к DirectX SDK (в обоих окнах: include и lib) расположены вверху списка, а пути к Windows SDK - в недоступной области, на несколько строк ниже.
Но! Заголовочным файлам DirectX SDK "жизненно важно", чтобы они включались после включений заголовков Windows SDK.
Важно!
Каталоги, пути к которым указаны в окнах "Каталоги включения" и "Каталоги библиотек" при компиляции считываются один за другим по списку сверху вниз. Поэтому для корректного указания путей надо разместить пути к Windows SDK выше, а к DirectX SDK - ниже по списку (чтобы они считывались последними).
В данной ситуации мы не можем поднять пути к Windows SDK, прописанные по умолчанию при создании Проекта, т.к. они расположены в специальной нередактируемой области (ограничение бесплатной версии MSVC++2010 Express). Но можем схитрить и добавить ещё раз пути к тем же самым каталогам Windows SDK, подняв эти строки выше строк DirectX SDK.
Выше мы указывали пути к DirectX SDK. Для путей к Windows SDK это делается аналогично. Начнём.
- Убедись, что MSVC++2010 запущена и в ней открыт Проект, с которым работаешь в данный момент.
- Убедись, что Windows SDK (в нашем случае версия 7) установлен на компьютере и ты уверенно можешь назвать полный путь к его каталогу.
- Жмём правой кнопкой мыши по названию Проекта. Во всплывающем меню выбираем пункт "Свойства".
Или в Главном меню выбираем Проект->Свойства. Или нажимаем Alt+F7.
В появившемся меню свойств проекта выбираем Свойства конфигурации -> Каталоги VC++ . В правой части этой страницы расположены пути ко всевозможным каталогам. Здесь нас, как и в прошлый раз, интересуют только 2 строки: Каталоги включения и Каталоги библиотек.
Указываем каталог включений (include) Windows SDK
- В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги включения. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
В появившемся меню "Каталоги включения" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к заголовочным (include) файлам Windows SDK. В нашем случае (Win7 x64) это C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
- Меняй порядок считывания каталогов включений с помощью кнопок с чёрными стрелками в верхней части окна "Каталоги вложений".
- Жмём "ОК".
Указываем каталог библиотек (lib) Windows SDK
- В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги библиотек. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
- В появившемся меню "Каталоги библиотек" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к папке с файлами библиотек (lib) Windows SDK. В нашем случае (Win7 x64) это C:\Program Files (x86)\MicrosoftSDKs\Windows\v7.0A\Lib. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
- Меняй порядок считывания каталогов вложений с помощью кнопок с чёрными стрелками в верхней части окна.
- Жмём "ОК".
- На Странице свойств тоже жмём "ОК".
- Сохрани Решение (File -> Save All). Готово.
Прописываем библиотеки d3d9.lib, d3dx9.lib и WinMM.LIB в окне "Дополнительные зависимости" (Additional dependencies) компоновщика (Linker)
Библиотеки d3d9.lib и d3dx9.lib расположены в папке с установленным DirectX SDK 9 (в нашем случае по пути C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86), пути к которому мы прописали выше.Библиотека WinMM.lib отвечает за мультимедиа-возможности приложения и расположена в каталоге с установленным Windows SDK (в нашем случае здесь: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib).
Т.к. мы создаём исполняемое приложение (исполняемый .exe-файл), а не библиотеку, то после компиляции полученный объектный модуль сразу линкуется путём вызова компоновщика (=linker). Так вот, этот самый компоновщик по ранее прописанным каталогам данные библиотеки не ищет. Поэтому их необходимо указывать отдельно в окне настроек Проекта, в разделе "Компоновщик". ОК, начинаем.
- Убедись, что MSVC++2010 запущена и в ней открыт наш текущий Проект.
- В Главном меню MS Visual C++ 2010 выбираем Проект -> Свойства (Project -> Properties).
- В появившемся окне установки свойств Проекта последовательно щёлкаем по раскрывающимся ветвям иерархического дерева: Свойства конфигурации -> Компоновщик -> Ввод (Configuration Properties -> Linker -> Input).
- В правой части, напротив строки "Дополнительные зависимости" жмём кнопку с чёрным треугольником.
- В всплывающем списке жмём "Изменить".
- В появившемся окне "Дополнительные зависимости" в верхнем поле ввода прописываем в столбик (один под другим) имена файлов трёх библиотек:
d3dx9.lib
WinMM.lib
Библиотека Winmm.lib отвечает за мультимедиа-возможности приложения и расположена в каталоге с установленным Windows SDK.
- Жмём ОК, ОК.
- Сохрани Решение (Файл->Сохранить все).
Компилируем Проект D3D9ASprite01
Наконец, наш тестовый Проект готов к компиляции.- Жми кнопку с зелёным треугольником на панели инструментов главного окна MSVC++2010 или F5 на клавиатуре.
Если весь код был введён без ошибок, после компиляции запустится приложение, отображающее окно с белым фоном, которое через секунду закрывается.
Скомпилированное .exe-приложение в нашем случае (Win7 x64) расположено по пути C:\Users\<Имя пользователя>\Documents\Visual Studio 2010\Projects\D3D9ASprite01\Debug .
Обрати внимание
Если попытаться запустить скомпилированный .exe-файл на компьютере без установленной MSVC++2010, то экзешник (скорее всего) "ругнётся" на отсутствующую библиотеку MSVCR100D.dll. Буква D в её имени означает Debug, т.е. данное приложение скомпилировано с отладочной конфигурацией (профилем), которая выставляется по умолчанию у каждого вновь создаваемого Проекта/Решения. При релизе игры приложение напротив, компилируют с конфигурацией Release (релиз). При этом при создании инсталлятора в дистрибутив с игрой добавляют т.н. набор библиотек времени выполнения (в нашем слчае MS Visual C++ 2010 Runtime Redistributable). Он устанавливается вместе с игрой, т.к. без него игра тупо не стартанёт. Если для Release-профиля такой набор нетрудно нагуглить (например здесь: https://www.mydigitallife.net/visual-c-2010-runtime-redistributable-package-x86-x64-ia64-free-download, 4,8 Мб для 64-разрядной версии ОС), то для запуска Debug-версии на отдельном компе на него потребуется установить целую MSVC++2010. Всё так сложно в том числе с целью не допустить утечек предрелизных разработок с компов игрокодерских компаний. Релиз есть релиз. А с дебаг-версиями, как правило, работают только сами игрокодеры, на своих компах отлавливая ошибки.
Конфигурации Debug и Release легко переключаются на странице свойств открытого Проекта (в MSVC++2010 в главном меню выбираем Проект->Свойства, в верхней части диалога видим всплывающий список "Конфигурация").
Работа над статьёй приостановлена
Причина: код м-ра Harbour успешно компилируется, но при запуске приложения его окно через секунду закрывается.В ходе выяснения причин было выяснено, что выполнение "спотыкается" при выполнении этого фрагмента:
... // Создаём объект дескриптора спрайта result = D3DXCreateSprite(d3ddev, &SpriteHandler); if(result != D3D_OK) { MessageBox(hWnd, "Спрайт не создан(", "Note", MB_OK); return NULL; } ...
Источники
1. Harbour J.S. Beginning Game Programming. - Thomson Course Technology, 2005
2. Thorn A. DirectX 9 graphics: the definitive guide to Direct3D. - Wordware Publishing, 2005
Последние изменения страницы Четверг 09 / Июнь, 2022 00:07:16 MSK
Последние комментарии wiki