天天看點

DirectX 遊戲程式設計之開篇

DirectX并不是一個單純的圖形API,它是由微軟公司開發的用途廣泛的API,它包含有Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多個元件,它提供了一整套的多媒體接口方案。

DirectX是一系列的COM對象或接口,Direct 3D隻是DirectX的一個部分,Direct3D是一個相當進階的類,它封裝了你運作2D和3D圖形所需要的全部硬體啊,軟體啊,以及其他。

COM

COM對象實際就是C++類,或者說是供你調用以實作一定目标的類内的函數。每個類都可以單獨而不是互相間配合才能進行工作,而且可以作為一個單獨元件解除安裝或加載而不影響程式的運作。獨立性是COM的最大特性之一。

COM的特點,讓DirectX 獨立于語言而向下相容。

一般将COM對象作為接口,将其視為C++類使用,我們所必須知道的僅是通過某個特定函數或另一個COM接口來擷取指向某一個COM接口的指針。通常使用CreateX()函數。獲得指針後就可以該接口的功能(接口内的方法)。

注意到建立COM接口不可使用C++的關鍵字new,而是特定的函數,同時使用完一個接口,應該地調用接口對應的Release方法而不是delete。

這是因為每一個對象都有其的應用計數(Reference Counter),當建立對象時,為該計數初始為1,當使用該對象時進行AddRef(),遞增計數,每次試圖删除進行Release(),隻有當引用計數為0,表明該對象正式删除,進行delete操作。

這樣保證了當我們進行一次Create操作時,我們獲得的是該對象指針,至于該指針是在哪裡new出來的我們不在需要關注,而隻需要Release,就能使該對象準确的時機被delete:

LPDIRECT3D9 d3d;
d3d = Direct3DCreate9(D3D_SDK_VERSION);    // create the Direct3D interface
d3d->Release();    // close and release Direct3D 
           

在D3D學習的過程我們需要的NEED:

  • Visual Studio 2010 以及以上版本
  • The DirectX SDK June 2010
  • C++基礎知識
  • 開發遊戲的強烈熱情

WIN32基礎

遊戲基本流程

1 Initialize the program:初始化程式如建立視窗,初始化Direct3D

2 Start the game:啟動遊戲

3 Get input from the player:擷取輸入,是遊戲與玩家的互動部分

4 Run the game logic, such as physics and AI:運作遊戲實體引擎、邏輯AI等

5 Render graphics:渲染圖形

6 Loop:進入遊戲循環

7 Cleanup:資源的釋放

WIN32視窗程式

1 注冊視窗類 RegisterClassEx

2 建立視窗 CreateWindowEx

3 顯示視窗 ShowWindow

4 消息循環 Loop GetMessage

以下為完整的WIN32視窗程式代碼

// include the basic windows header file
#include <windows.h>

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
	UINT message,
	WPARAM wParam,
	LPARAM lParam);

// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow)
{
	// the handle for the window, filled by a function
	HWND hWnd;
	// this struct holds information for the window class
	WNDCLASSEX wc;

	// clear out the window class for use
	ZeroMemory(&wc, sizeof(WNDCLASSEX));

	// fill in the struct with the needed information
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
	wc.lpszClassName = L"WindowClass";

	// register the window class
	RegisterClassEx(&wc);

	// create the window and use the result as the handle
	hWnd = CreateWindowEx(NULL,
		L"WindowClass",    // name of the window class
		L"First Window",   // title of the window
		WS_OVERLAPPEDWINDOW,    // window style
		300,    // x-position of the window
		300,    // y-position of the window
		500,    // width of the window
		400,    // height of the window
		NULL,    // we have no parent window, NULL
		NULL,    // we aren't using menus, NULL
		hInstance,    // application handle
		NULL);    // used with multiple windows, NULL

	// display the window on the screen
	ShowWindow(hWnd, nCmdShow);

	// enter the main loop:

	// this struct holds Windows event messages
	MSG msg;

	// wait for the next message in the queue, store the result in 'msg'
	while(GetMessage(&msg, NULL, 0, 0))
	{
		// translate keystroke messages into the right format
		TranslateMessage(&msg);

		// send the message to the WindowProc function
		DispatchMessage(&msg);
	}

	// return this part of the WM_QUIT message to Windows
	return msg.wParam;
}

// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	// sort through and find what code to run for the message given
	switch(message)
	{
		// this message is read when the window is closed
	case WM_DESTROY:
		{
			// close the application entirely
			PostQuitMessage(0);
			return 0;
		} break;
	}

	// Handle any messages the switch statement didn't
	return DefWindowProc (hWnd, message, wParam, lParam);
}
           

遊戲循環消息處理函數PeekMessage與GetMessage的差別之處:它不在等待消息,相當于對視窗消息隊列消息進行檢查而已,是以我們必須另外處理循環的退出情況。

while(TRUE)
{
	// Check to see if any messages are waiting in the queue
	while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		// translate keystroke messages into the right format
		TranslateMessage(&msg);

		// send the message to the WindowProc function
		DispatchMessage(&msg);
	}

	// If the message is WM_QUIT, exit the while loop
	if(msg.message == WM_QUIT)
		break;

	// Run game code here
	// ...
	// ...
}
           

Direct3D程式

  1. 建立全局變量與函數原型
  2. 寫初始化Direct3D函數,建立Direct3D Device
  3. 寫渲染函數
  4. 關閉與釋放Direct3D資源的函數

1 建立全局變量與函數原型

#include <windows.h>
#include <d3d9.h>

// include the Direct3D Library file
#pragma comment (lib, "d3d9.lib")

// global declarations
LPDIRECT3D9 d3d;    // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device class

// function prototypes
void initD3D(HWND hWnd);    // sets up and initializes Direct3D
void render_frame(void);    // renders a single frame
void cleanD3D(void);    // closes Direct3D and releases memory

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
           

2 寫初始化Direct3D函數,建立Direct3D Device

初始化Direct3D的步驟:

  • 擷取IDirect3D9指針(Direct3DCreate9)
  • 檢查裝置性能(D3DCAPS9 -Device Capabilities)
  • 填充D3DPRESENT_PARAMETERS結構,該結構用于指定建立IDirect3DDevice9對象的特性
  • 建立IDirect3DDevice9對象,其代表了我們顯示圖像的實體裝置
// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
	d3d = Direct3DCreate9(D3D_SDK_VERSION);    // create the Direct3D interface

	D3DPRESENT_PARAMETERS d3dpp;    // create a struct to hold various device information

	ZeroMemory(&d3dpp, sizeof(d3dpp));    // clear out the struct for use
	d3dpp.Windowed = TRUE;    // program windowed, not fullscreen
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    // discard old frames
	d3dpp.hDeviceWindow = hWnd;    // set the window to be used by Direct3D

	// create a device class using this information and information from the d3dpp stuct
	d3d->CreateDevice(D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,
		&d3ddev);
}
           

3 寫渲染函數

// this is the function used to render a single frame
void render_frame(void)
{
    // clear the window to a deep blue
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);

    d3ddev->BeginScene();    // begins the 3D scene

    // do 3D rendering on the back buffer here

    d3ddev->EndScene();    // ends the 3D scene

    d3ddev->Present(NULL, NULL, NULL, NULL);    // displays the created frame
}
           

4 關閉與釋放Direct3D資源的函數

// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
	d3ddev->Release();    // close and release the 3D device
	d3d->Release();    // close and release Direct3D
}
           

REL

網絡教程:

DirectXTutorial.com

書籍:

《DIRECTX 9.0 3D 遊戲開發程式設計基礎》 Frank D.Luna 清華大學出版社

《Windows程式設計第五版》