Khởi tạo cửa sổ với DirectX 9
Cách để khởi tạo một cửa sổ cũng như các kiến thức liên quan để khởi đầu cho việc lập trình game với DirectX 9.
Nhắc lại kiến thức
Game được hiện thực như 1 đối tượng trong chương trình, đối tượng đó trải qua 3 giai đoạn chính gồm: khởi Tạo (init), chạy (run) và thoát (exit).
Tạo class Game
#ifndef __GAME_H__ #define __GAME_H__ #include <d3d9.h> #define WIDTH 800 #define HEIGHT 600 class Game { private: int m_Width; int m_Height; bool m_IsWindow; HINSTANCE m_HandleInstance; HWND m_HandleWindow; LPDIRECT3D9 m_lpDirect3D; LPDIRECT3DDEVICE9 m_lpDirect3DDevice; static LRESULT CALLBACK WndProceduce(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); public: Game(int scr_Width, int scr_Height, bool isWindow); bool initHandleWindow(); bool initDirectX3DEnviroment(); bool initDirect3DDevice(); void GameInit(); void GameRun(); void GameExit(); }; #endif
Giải thích các thuộc tính
m_Width
,m_Height
: các thuộc tính quy định chiều dài và rộng của cửa sổ Game.m_IsWindow
: quy định cửa sổ sẽ hiển thị window hoặc full màn hình.m_HandleInstance
:HINSTANCE
là 1 thuộc tính đại diện cho ứng dụng / game khi được hệ điều hành chạy.m_HandleWindow
: mỗi ứng dụng / game sẽ có thể chứa nhiều cửa sổ, mỗi cửa sổ cần có 1 định danh riêng, định danh đó chính làHWND
.m_lpDirect3D
:LPDIRECT3D9
là một Direct3D Object, biến này cần thiết cho việc khởi tạo Device để thao tác vẽ trong Game.m_lpDirect3DDevice
:LPDIRECT3DDEVICE9
dùng để lưu thông tin của Device sử dụng thao tác vẽ trong chương trình.WndProceduce(...)
: hàm callback dùng để lắng nghe các sự kiện của cửa sổ Game khi người dùng tương tác.Game(...)
: hàm tạo của GameObject.initHandleWindow(...)
: khởi tạo các thuộc tính cần thiết cho cửa sổ.initDirectX3DEnviroment(...)
: khởi tạo môi trường lập trìn DirectX.initDirect3DDevice(...)
: Khởi tạo thiết bị DirectX.GameInit(...)
: đặt tất cả các hàm khởi tạo cần thiết trước lúc chương trình chạy.GameRun(...)
: update Game.GameExit(...)
: giải phóng các tài nguyên cần được giải phóng trước lúc chương trình thoát.
Hiện thực các phương thức
Hàm tạo
Khởi tạo các giá trị ban đầu cho ứng dụng.
Game::Game(int scr_Width, int scr_Height, bool isWindow) { this->m_Width = scr_Width; this->m_Height = scr_Height; this->m_IsWindow = isWindow; this->m_HandleInstance = 0; this->m_HandleWindow = 0; this->m_lpDirect3D = 0; this->m_lpDirect3DDevice = 0; }
initHandleWindow
Ở class này, khởi tạo các thuộc tính cần thiết cho cửa sổ, giúp cửa sổ hiển thị và đăng ký các sự kiện khi người dùng thao tác với cửa sổ.
bool Game::initHandleWindow() { WNDCLASSEX WndcEx; ZeroMemory(&WndcEx, sizeof(WndcEx)); WndcEx.cbSize = sizeof(WNDCLASSEX); WndcEx.hInstance = this->m_HandleInstance; WndcEx.lpfnWndProc = (WNDPROC) WndProceduce; WndcEx.lpszClassName = "Game"; if (!RegisterClassEx(&WndcEx)) { return false; } this->m_HandleWindow = CreateWindow( "Game", // đặt trung với WndcEx.lpszClassName TITLE, // TITLE của cửa sổ #define TITLE "GAME" WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, // style của cửa sổ 100, // tọa độ x khi cửa sổ xuất hiện 100, // tọa độ y khi cửa sổ xuất hiện this->m_Width, // chiều dài cửa sổ this->m_Height, // chiều cao cửa sổ 0, // handle window parent của của sổ hiện tại. Để là 0 0, // handle đến Menu. Để là 0 this->m_HandleInstance, // Handle Instance của ứng dụng 0); // giữ nguyên theo default là 0 if (!this->m_HandleWindow) // Kiểm tra tạo thành công. { return false; } ShowWindow(m_HandleWindow, SW_SHOW); // show cửa sổ lên màn hình UpdateWindow(m_HandleWindow); // Update cửa sổ theo thời gian return true; }
initDirectX3Denviroment
Hàm này tác dụng khởi tạo đối tượng Direct3D
, cần đối tượng này để làm việc với DirectX ở các bài viết sau.
bool Game::initDirectX3DEnviroment() { this->m_lpDirect3D = Direct3DCreate9(D3D_SDK_VERSION); if (m_lpDirect3D){ return true; } return false; }
initDirect3DDevice
Cần dùng D3DPRESENT_PARAMETERS
để thao tác tạo Direct3D Device, dùng vẽ các Game Object lên màn hình sau này.
bool Game::initDirect3DDevice() { D3DPRESENT_PARAMETERS d3dpp; // khai báo biến ZeroMemory(&d3dpp, sizeof(d3dpp)); // Khởi tạo vùng nhớ d3dpp.BackBufferCount = 1; // Số lượng Back buffer d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // Chọn UNKNOW, DirectX sẽ tự chọn 1 định dạng phù hợp cho Device d3dpp.BackBufferHeight = HEIGHT; // chiều cao cảu BackBuffer d3dpp.BackBufferWidth = WIDTH; // Chiều dài của BackBuffer d3dpp.Windowed = true; // Window ở dạng cửa sổ, không phải full màn hình d3dpp.hDeviceWindow = this->m_HandleWindow; // Gán HandleWindow cho Device d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Phương thức swap của Buffer m_lpDirect3D->CreateDevice( D3DADAPTER_DEFAULT, // Chọn DEFAULT ADAPTER D3DDEVTYPE_HAL, // m_HandleWindow, // Handle Window của của sổ D3DCREATE_HARDWARE_VERTEXPROCESSING, // Hard ware vertex processing &d3dpp, &m_lpDirect3DDevice); // Hàm tạo Device if(FAILED(m_lpDirect3DDevice)) { return false; } return true; }
GameInit
Hàm này lần lượt gọi các khởi tạo đã xây dựng từ trước.
void Game::GameInit() { initHandleWindow(); initDirectX3DEnviroment(); initDirect3DDevice(); }
GameRun
Hàm này thực hiện toàn bộ update của Game, sử dụng vòng lặp while để duy trì cửa sổ luôn hoạt động trong quá trình chạy Game.
void Game::GameRun() { MSG msg; ZeroMemory(&msg, sizeof(msg)); // Tạo một Mesage để lắng nghe các sự kiện của cửa sổ while (true) { if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) // Lấy message và truyền vào biến msg đã khai báo { if (msg.message == WM_QUIT) // Kiểm tra nếu msg yêu cầu QUIT ứng dụng thì ứng dụng sẽ thoát break; TranslateMessage(&msg); // xử lý input và chuyển vào msg DispatchMessage(&msg); // gửi message đến hàm WndProceduce để xử lý } else { // Begin Draw something in Game m_lpDirect3DDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(100, 100, 100), 1.0f, 0); // Clear cửa sổ 1 lần trước khi vẽ lên if (m_lpDirect3DDevice->BeginScene()) { // Game Render Here m_lpDirect3DDevice->EndScene(); } m_lpDirect3DDevice->Present(0, 0, 0, 0); // Thể hiện tất cả những gì đã vẽ lên màn hình } } }
GameExit
Hàm có chức năng giải phóng vùng nhớ không cần dùng đến lúc thoát Game.
void Game::GameExit() { if (this->m_lpDirect3D) { this->m_lpDirect3D->Release(); this->m_lpDirect3D = NULL; } if (this->m_lpDirect3DDevice) { this->m_lpDirect3DDevice->Release(); this->m_lpDirect3DDevice = NULL; } }
WndProceduce
Hàm nhận các sự kiện của cửa sổ và xử lý ở đây, ví dụ khi nhận sự kiện WM_DESTROY
thì cửa sổ sẽ đóng xuống.
LRESULT CALLBACK Game::WndProceduce(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, message, wParam, lParam); }
Hàm WinMain
Chương trình của bắt đầu chạy tại đây.
#include<d3d9.h> #include "Game.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstace, LPSTR lpStrCmdLine, int nShowCmd) { Game mygame(WIDTH, HEIGHT, false); mygame.GameInit(); mygame.GameRun(); mygame.GameExit(); return 0; }