Post date: Jul 4, 2011 5:11:54 PM
Như đã đề cập ở trên, game cũng như một bộ phim. Nếu như phim cần màn hình để trình chiếu, thì Game cần một cửa sỗ để hiện thị.
Ứng với mỗi platform, có những cách riêng để thiết lập cửa sổ.
Nội dung mục này sẽ trình bày về cách tạo cửa sổ cho VsWin32
Ngoài cách truyền thống là dùng IDE tạo cửa sổ, ta có thể tạo cửa sổ window form bằng code.
CVSView.h
#ifndef __CVSVIEW_H__ #define __CVSVIEW_H__ #include "Header.h" #if (CONFIG_PLATFORM==PLATFORM_WIN32_VS) namespace GameTutor { class CVSView { public: CVSView(__INT32 w, __INT32 h, bool fullscreen = false, const char*name = 0); virtual ~CVSView(); void Update(); static CVSView* s_pInstance; __INT32 GetWidth() {return m_iWidth;} __INT32 GetHeight() {return m_iHeight;} __INT32 IsFullScreen() {return m_isFullScreen;} private: __INT32 m_iWidth; __INT32 m_iHeight; bool m_isFullScreen; char *m_strTitle; void InitClientWindow(); void Destroy(); public: HGLRC m_hGLRC; HWND m_hwndWindow; HDC m_hGameWndDC; static LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ); }; } #endif //(CONFIG_PLATFORM==PLATFORM_WIN32_VS) #endif
CVSView.cpp
#include "CVSView.h" #include "CGame.h" #include "CDevice.h" #if (CONFIG_PLATFORM==PLATFORM_WIN32_VS) namespace GameTutor { CVSView* CVSView::s_pInstance = 0; //---------------------------------------- // Constructor //---------------------------------------- CVSView::CVSView(int w, int h, bool fullscreen, const char*name):m_iWidth(w), m_iHeight(h), m_isFullScreen(false), m_hGLRC(0), m_hwndWindow(0), m_hGameWndDC(0) { s_pInstance = this; if (name) { m_strTitle = new char[strlen(name) + 1]; strcpy(m_strTitle, name); } else { char *xname = "Untitle"; m_strTitle = new char[strlen(xname) + 1]; strcpy(m_strTitle, xname); } InitClientWindow(); CDevice::GetInstance()->SleepEx(3000); //sleep to avoid lag when launch game } //---------------------------------------- // Destructor //---------------------------------------- CVSView::~CVSView() { Destroy(); delete m_strTitle; } //---------------------------------------- // Init win32 client window //---------------------------------------- void CVSView::InitClientWindow() { //get current instant HINSTANCE hInstance = GetModuleHandle(0); //---------------------------------- // init WNDCLASSEX WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = 0;//LoadIcon(hInstance, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = 0; wcex.lpszClassName = "main"; wcex.hIconSm = 0;//LoadIcon(wcex.hInstance, IDI_APPLICATION); if (! RegisterClassEx( &wcex ) ) { return; // ERR, SO QUIT } //---------------------------------- // init HWND DWORD style = WS_POPUP; if(!m_isFullScreen) { style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; } RECT clientSize; clientSize.top = 0; clientSize.left = 0; clientSize.right = m_iWidth; clientSize.bottom = m_iHeight; AdjustWindowRect(&clientSize, style, FALSE); const int realWidth = clientSize.right - clientSize.left; const int realHeight = clientSize.bottom - clientSize.top; int windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; int windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; if(!m_isFullScreen) { m_hwndWindow = CreateWindow( "main", m_strTitle, style, windowLeft, windowTop, realWidth, realHeight, NULL, NULL, hInstance, NULL); } else { m_hwndWindow = CreateWindow( "main", m_strTitle, style, 0, 0, m_iWidth, m_iHeight, NULL, NULL, hInstance, NULL); } m_hGameWndDC = GetDC(m_hwndWindow); ShowWindow( m_hwndWindow, SW_SHOW ); UpdateWindow( m_hwndWindow ); if(!m_isFullScreen) { MoveWindow(m_hwndWindow, windowLeft, windowTop, realWidth, realHeight, TRUE); } SetActiveWindow(m_hwndWindow); SetForegroundWindow(m_hwndWindow); if(m_isFullScreen) { DEVMODE dm; memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(DEVMODE); dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; dm.dmPelsWidth = m_iWidth; dm.dmPelsHeight = m_iHeight; dm.dmBitsPerPel = 32; ChangeDisplaySettings(&dm, CDS_FULLSCREEN); } } //---------------------------------------- // update win32 message //---------------------------------------- void CVSView::Update() { // handle win32 message MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); if (msg.hwnd == m_hwndWindow) { //WndProc(m_hwndWindow, msg.message, msg.wParam, msg.lParam); DispatchMessage(&msg); } } } //---------------------------------------- // Destroy win32 window //---------------------------------------- void CVSView::Destroy() { if (m_isFullScreen) { ChangeDisplaySettings(NULL, 0); } } //---------------------------------------- // Win32 Message Callback //---------------------------------------- LRESULT CALLBACK CVSView::WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) { switch( message ) { case WM_CREATE: return 0; break; case WM_PAINT: // paint event PAINTSTRUCT ps; BeginPaint(hwnd, &ps); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: // killing the window CGame::GetInstance()->Exit(); PostQuitMessage( 0 ); return 0; } return DefWindowProc(hwnd, message, wparam, lparam); } } #endif
Do việc tạo cửa sổ Win32 này là đặc thù cho platform win32-VS, do đó, ta đặt nội dung bên trong cờ CONFIG_PLATFORM==PLATFORM_WIN32_VS
Do ứng với mỗi platform có một cửa sổ khác nhau, ta thiết kế lớp CViewController với dạng template. Template này đại diện cho kiểu cửa sổ cho từng platform (ví dụ CSView cho win32-vs)
Các lớp view được thống nhất một số hàm:
Source:
CViewController.h
#ifndef __CVIEWCONTROLLER_H__ #define __CVIEWCONTROLLER_H__ #include "Header.h" #include "CVSView.h" namespace GameTutor { template <class T> class CViewController { public: static CViewController* GetInstance() {return s_pInstance;} static void CreateView(int width, int height, bool fullscreen = false, const char*name = 0) { if (!s_pInstance) { s_pInstance = new CViewController(); //create a view template s_pInstance->m_pView = new T(width, height, fullscreen, name); } } T* GetView() { return m_pView; } virtual ~CViewController() { if (m_pView) delete m_pView; } protected: CViewController(): m_pView(0) {} static CViewController* s_pInstance; T* m_pView; }; } #endif
CViewController.cpp
#include "CViewController.h" namespace GameTutor { CViewController<VIEWCLASS>* CViewController<VIEWCLASS>::s_pInstance = 0; }
Để qui định lớp View nào được sử dụng, ta bổ sung thông tin vào Header.h như sau:
Header.h
... #if (CONFIG_PLATFORM==PLATFORM_WIN32_VS) # define VIEWCLASS CVSView #else # define VIEWCLASS #endif ...
Để tích hợp cửa sổ vào game, ta thay đổi nội dung hàm Run của CGame:
CGame.cpp
... void CGame::Run() { this->Init(); //init view if (!CViewController::GetInstance()) { CViewController::GetInstance()->CreateView(640, 480); } while (m_isAlived) { CFpsController::GetInstance()->BeginCounter(); if (m_isPaused) { CStateManagement::GetInstance()->Update(true); } else { CStateManagement::GetInstance()->Update(false); } CViewController::GetInstance()->GetView()->Update(); CFpsController::GetInstance()->EndCounter(); } //force clean up current state CStateManagement::GetInstance()->SwitchState(0); CStateManagement::GetInstance()->Update(false); //Destroy view delete CViewController::GetInstance(); Destroy(); }
Download