ITCS - Разработка компьютерных игр. Часть 5 - РАЗРАБОТКА КОМПЬЮТЕРНЫХ ИГР
Сегодня: Понедельник, 05.12.2016, 23:38 (МСК)| Здравствуйте, Гость| Мой профиль | Регистрация | Вход | RSS

Работаем с VirtualDub

Моделирование в Maxon Cinema4D

Эргономика компьютерных клавиатур

Новинки в области цифровых камер

Программы — виртуальные гитаристы
Главная » РАЗРАБОТКА КОМПЬЮТЕРНЫХ ИГР

Разработка компьютерных игр. Часть 5

26.07.2010
Все главные и существенные вводные моменты мы уже рассмотрели, осталось только пройтись по ключевым примерам DirectX SDK, что займет несколько выпусков. Дальнейшее развитие серии зависит от вас, то есть, можете выбрать пункт, о котором вы хотите узнать прежде всего:
  • Создание объектов и персонажей в Direct3D, рисование, текстурирование, анимация.
  • Создание карт, визуализация ландшафта.
  • Освещение, шейдеры, HLSL.
  • Работа с системами частиц.
  • Разработка интерфейса.
  • Искусственный интеллект.
  • Сетевое программирование.
  • Программирование звука для игр.
  • Перевод игр на консоли.
Все темы достаточно объемны, поэтому вам предлагается на выбор: с чего лучше стартовать в следующем году. Причем, будут изменения в формате представления материалов, они уже не будут выходить как общая серия «Разработка компьютерных игр», а разбиваться тематически. В общем, пишите все ваши пожелания на почтовый ящик или в гостевую книгу. 


Инициализация Direct3D


Теперь с багажом полученных знаний мы начнем внедряться в программирование. Осознанно. Открываем самый первый пример из документации к SDK, который расположен по адресу …\Program Files\Microsoft DirectX SDK\Samples\C++\Direct3D\Tutorials\Tut01_CreateDevice, в рамках нашей Visual Studio. Ваш покорный слуга опирается на Visual Studio 2008, хотя данный момент не сильно принципиален. Смотрим файл CreateDevice.cpp (полный листинг без объяснений в конце материала).
Заголовочный файл DirectX SDK подключается следующим образом:

#include <d3d9.h>

Итак, первым этапом инициализации идет запрос указателя на интерфейс IDirect3D, который применяется для получения информации об аппаратных устройствах компьютера, а также для создания интерфейса IDirect3DDevice9, который будет являться объектом С++, представляющим аппаратное устройство для вывода трехмерной графики (визуализации). Этому соответствуют строки:

LPDIRECT3D9 g_pD3D       = NULL; 
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; 

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

LPDIRECT3D9 direct3d = NULL;
LPDIRECT3DDEVICE9 device = NULL; 

…но все же будем опираться на листинг программы c учетом ее названий переменных.

HRESULT InitD3D( HWND hWnd )
{

Init3D — функция инициализации главного окна приложения, содержащая код инициализации Direct3D. Здесь содержатся ключевые строки. 
Создавая главный объект, мы вызываем функцию Direct3DCreate9 с единственным параметром D3D_SDK_VERSION, который является предопределенной константой, описанной в заголовочном модуле (d3d9.h), и указывает на версию DirectX. 
То есть, в простейшем виде можно записать:

g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);

В нашем случае мы создаем главный объект следующим образом, причем нам нужно просто узнать, установлен ли DirectX вообще:

if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION) ) )
return E_FAIL;

Следующим этапом подключается структура, используемая для создания интерфейса IDirect3DDevice9:

D3DPRESENT_PARAMETERS d3dpp; 
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; 

Теперь расшифруем: ZeroMemory () — заполняем указанную строку нулями, Windowed=True указывает на то, что запуск будет происходить в окне, в рамках SwapEffect задается режим действия механизма двойной буферизации, в данном случае мы выбрали форсированный вариант D3DSWAPEFFECT_DISCARD, BackBufferFormat указывает на то, какой формат буфера будет использоваться. 
Теперь мы создаем устройство вывода (визуализации):

if (FAILED(g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice) ) )
{
return E_FAIL;
}
return S_OK;

Отдельно стоит сказать, что в книгах по программированию DirectX вы чаще всего встретите несколько отличный подход к написанию кода, то есть, там все выполняется без условий if. В SDK же это показано в рамках более осторожных методов, то есть, «если это возможно…».
Теперь расшифровываем строку. Вызывая метод CreateDevice мы получаем ссылку на IDirect3DDevice9, с помощью которого производится визуализация. Далее все вам должно быть знакомо, хотя пробежаться по параметрам еще раз не помешает: D3DADAPTER_DEFAULT указывает на номер графического адаптера, установленного в системе, D3DDEVTYPE_HAL — тип устройства, и в данном случае мы подразумеваем полностью аппаратную обработку (если бы указали D3DDEVTYPE_REF, то была бы программная), третий параметр позволяет задать окно (Handle), в которое будет производиться выход сцены, D3DCREATE_SOFTWARE_VERTEXPROCESSING указывает на программную обработку вершин, потому как, например, видеоадаптер может ее не поддерживать, в &d3dpp хранятся параметры создаваемого устройства вывода, &g_pd3dDevice — имя переменной, куда будет помещен результат.
На самом деле, не смотря на кажущуюся сложность, при близком рассмотрении все оказывается достаточно простым. Причем в рамках этого листинга не делается одна вещь, которую мы описывали ранее, а именно, проверка возможностей графического адаптера.
Дальше в коде идет функция очистки памяти. Напомню, что мы имеем дело с COM-объектами, и для их удаления не подходит ключевое слово delete, а вместо него используется метод Release.

VOID Cleanup()
{
    if( g_pd3dDevice != NULL) 
        g_pd3dDevice->Release();

    if( g_pD3D != NULL)
        g_pD3D->Release();

Теперь наступила реализация вывода пустого окна, закрашенного в определенный цвет, в указанном примере, синий. Для этого используем метод Clear() интерфейса IDirect3DDevice9. 

VOID Render()
{
    if( NULL == g_pd3dDevice )
        return;

Закрашиваем вторичный буфер в синий цвет:

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

Начало сцены:

    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
//здесь помещаются объекты сцены
        g_pd3dDevice->EndScene();
    }

Вывод содержимого вторичного буфера на дисплей с помощью метода Present() интерфейса IDirect3DDevice9.  
    
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

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

INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{

Определяемся с оконным классом:  
  
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, 
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                      L"D3D Tutorial", NULL };
    RegisterClassEx( &wc );

Создание окна приложения с размерами 300х300 пикселей:

    HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 01: CreateDevice", 
                              WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                              NULL, NULL, wc.hInstance, NULL );

Инициализация Direct3D:

    if( SUCCEEDED( InitD3D( hWnd ) ) )
    { 

Показать окно:  
      
ShowWindow( hWnd, SW_SHOWDEFAULT ); 
UpdateWindow( hWnd );

Запуск цикла обработки сообщений:

        MSG msg; 
        while( GetMessage( &msg, NULL, 0, 0 ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }
    UnregisterClass( L"D3D Tutorial", wc.hInstance );
    return 0;

Каждый раз при обновлении цикла DispatchMessage вызывает функцию обработки системных сообщений MsgProc, которая прописана отдельно:

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            Cleanup();
            PostQuitMessage( 0 );
            return 0;

        case WM_PAINT:
            Render();
            ValidateRect( hWnd, NULL );
            return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

Другими словами, программа ждет, пока выполнится закраска WM_PAINT, после чего начинает перерисовывать. А как работают Cleanup() и Render() мы можем увидеть выше.
В результате, при запуске программы, пред нами появляется окно, закрашенноев однотонный синий цвет.
В большинстве случаев листинги следует рассматривать от функции WinMain, но в нашем случае просмотр сверху-вниз оправдан.
Второй пример Tutorial02 из DirectX SDK, в котором выводится треугольник с заданными вершинами и градиентной заливкой, мы уже рассматривали, то есть… к самостоятельному изучению.

Тест

На самом деле, в качестве тестового задания попробуйте несколько перевернуть описание нашего примера и самостоятельно сделать блок-схему, логически построенную от WinMain(), а не от создания Direct3D-объекта. То есть, мы просмотрели листинг сверху-вниз, и в данном случае это не было неудобным, но в ряде случаев правильнее "плясать" от Main().

Полный код файла CreateDevice.cpp, который мы только что рассмотрели


// File: CreateDevice.cpp
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------
#include <d3d9.h>
#pragma warning( disable : 4996 )
#include <strsafe.h>
#pragma warning( default : 4996 ) 
//------------------------
// Global variables
//------------------------
LPDIRECT3D9 g_pD3D = NULL; 
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; 
//---------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//---------------------------
HRESULT InitD3D( HWND hWnd )
{
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;
//--------------------------
D3DPRESENT_PARAMETERS d3dpp; 
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
//-------------------------
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }
//------------------------
    return S_OK;
}
//-----------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------
VOID Cleanup()
{
    if( g_pd3dDevice != NULL) 
        g_pd3dDevice->Release();

    if( g_pD3D != NULL)
        g_pD3D->Release();
}
//----------------------
// Name: Render()
// Desc: Draws the scene
//---------------------
VOID Render()
{
    if( NULL == g_pd3dDevice )
        return;
// Clear the backbuffer to a blue color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// Begin the scene
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
 {
// Rendering of scene objects can happen here
// End the scene
g_pd3dDevice->EndScene();
 }
// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
//-------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
 {
 case WM_DESTROY:
 Cleanup();
 PostQuitMessage( 0 );
 return 0;

 case WM_PAINT:
 Render();
 ValidateRect( hWnd, NULL );
 return 0;
 }
return DefWindowProc( hWnd, msg, wParam, lParam );
}
//----------------------
// Name: wWinMain()
// Desc: The application's entry point
//----------------------
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, 
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                      L"D3D Tutorial", NULL };
RegisterClassEx( &wc );
//---------------------
HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 01: CreateDevice", 
                              WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                              NULL, NULL, wc.hInstance, NULL );
// Initialize Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
 { 
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// Enter the message loop
MSG msg; 
while( GetMessage( &msg, NULL, 0, 0 ) )
  {
 TranslateMessage( &msg );
 DispatchMessage( &msg );
  }
 }
UnregisterClass( L"D3D Tutorial", wc.hInstance );
return 0;
}


Перепечатка материалов или их фрагментов возможна только с согласия автора.








Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Ассоциация боевых роботов
Рекомендуем...
Новости

Разделы

Опросы

Какой язык программирования вы считаете наиболее актуальным сегодня?
Всего ответов: 308

Друзья

3D-кино






Найти на сайте:








Об авторе       Контакты      Вопрос-ответ        Хостинг от uCoz