このページはゲームループの基礎講座シリーズの付録Bです。
ここには、この講座で紹介してる「ゲームのフレームワーク関数」である GameMainLib.cpp のソース・ファイルを紹介します。(戻る)
使い方
ゲーム・プログラマは、次の手順で WinMain 関数に記述します。
- GameMainInit 関数でスクリーンの横幅、高さ、フレーム数(FPS)を設定する。
- GameMainCreate 関数でゲーム・ウインドウを作成する。
- GameMainRun 関数にゲームの4つの基本処理を行う関数名を渡して実行する。
- エラーが発生した時のために GameMainErrMsg 関数を呼び出す記述を書く。
//------------------------------------------------ // メイン関数(OK) //------------------------------------------------ extern int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR, int nCmdShow ) { LPCTSTR lpClassName = TEXT("GameNameWndClass"); LPCTSTR lpTitleName = TEXT("ゲームのタイトル"); if ( GameMainInit(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_FPS) ){ if ( GameMainCreate(hInstance,lpClassName,lpTitleName,nCmdShow) ){ return GameMainRun( funcGameInit, funcGameTerm, funcGameUpdate, funcGameDraw ); } } return GameMainErrMsg( NULL, TEXT("WinMain関数") ); }
GameMainLib.cpp
//------------------------------------------------------------------------------ // ゲームのフレームワーク関数 //------------------------------------------------------------------------------ #include <Windows.h> // WinMM.Lib #include "GameMainLib.h" //------------------------------------------------ // break 付きのキーワード //------------------------------------------------ #define CASE break;case #define DEFAULT break;default //------------------------------------------------ // ウインドウのスタイル //------------------------------------------------ #define WINDOW_STYLE (WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME|WS_MAXIMIZEBOX)) //------------------------------------------------ // グローバル変数 //------------------------------------------------ static HWND gWnd; // ウインドウのハンドル static UINT gFPS; // フレームの更新間隔 static BOOL gPause; // フレームの一時停止 static LONG gWidth; // スクリーンの横幅 static LONG gHeight; // スクリーンの縦幅 static LONG gErrCode; // エラー・コード値 //------------------------------------------------ // ウインドウのプロシージャ関数 //------------------------------------------------ static LRESULT CALLBACK mainWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { HDC hScreenDC = (HDC)GetWindowLong(hWnd,GWL_USERDATA); switch ( uMsg ){ CASE WM_CREATE: hScreenDC = GameMainMemDC( hWnd, gWidth, gHeight ); SetWindowLong( hWnd, GWL_USERDATA, (LONG)hScreenDC ); CASE WM_CLOSE: DeleteDC( hScreenDC ); DestroyWindow( hWnd ); CASE WM_DESTROY: PostQuitMessage( 0 ); CASE WM_PAINT: { PAINTSTRUCT ps; HDC hDC; hDC = BeginPaint( hWnd, &ps ); BitBlt( hDC, 0, 0, gWidth, gHeight, hScreenDC, 0, 0, SRCCOPY ); EndPaint( hWnd, &ps ); } CASE WM_ACTIVATE: { LONG nActive = LOWORD(wParam); BOOL bMinimized = HIWORD(wParam); if ( nActive == WA_INACTIVE ){ // 非アクティブ時 gPause = TRUE; } else if ( bMinimized ){ // アクティブ時(最小化) gPause = TRUE; } else{ gPause = FALSE; // アクティブ時(通常) } } CASE WM_ENDSESSION: PostMessage( hWnd, WM_CLOSE, 0, 0 ); CASE WM_LBUTTONDOWN: SendMessage( hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0 ); CASE WM_LBUTTONDBLCLK: SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0, (SWP_NOMOVE|SWP_NOSIZE) ); CASE WM_RBUTTONDBLCLK: SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, (SWP_NOMOVE|SWP_NOSIZE) ); CASE WM_ERASEBKGND: return 1; /* 何も処理しない⇒塗り潰した */ DEFAULT: return DefWindowProc( hWnd, uMsg, wParam, lParam ); } return 0; } //------------------------------------------------ // ウインドウ・クラスの登録 //------------------------------------------------ static ATOM funcWindowClass( HINSTANCE hInstance, LPCTSTR lpClassName ) { WNDCLASSEX wcex = { 0 }; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_DBLCLKS; wcex.lpfnWndProc = mainWindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon( NULL, IDI_APPLICATION ); wcex.hIconSm = LoadIcon( NULL, IDI_APPLICATION ); wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = (HBRUSH)GetStockObject( NULL_BRUSH ); wcex.lpszMenuName = NULL; wcex.lpszClassName = lpClassName; return RegisterClassEx( &wcex ); } //------------------------------------------------ // ウインドウ・サイズの設定 //------------------------------------------------ static VOID funcSetClientSize( HWND hWnd, LONG sx, LONG sy ) { RECT rc1; RECT rc2; GetWindowRect( hWnd, &rc1 ); GetClientRect( hWnd, &rc2 ); sx += ((rc1.right - rc1.left) - (rc2.right - rc2.left)); sy += ((rc1.bottom - rc1.top) - (rc2.bottom - rc2.top)); SetWindowPos( hWnd, NULL, 0, 0, sx, sy, (SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE) ); } //------------------------------------------------ // ウインドウの作成 //------------------------------------------------ static HWND funcCreateWindow( HINSTANCE hInstance, LPCTSTR lpClassName, LPCTSTR lpTitleName, int nCmdShow ) { gWnd = CreateWindowEx( 0, // 拡張ウインドウ・スタイル lpClassName, // ウインドウのクラス名 lpTitleName, // ウインドウのタイトル名 WINDOW_STYLE, // ウインドウのスタイル CW_USEDEFAULT, // ウインドウの横軸位置 CW_USEDEFAULT, // ウインドウの縦軸位置 CW_USEDEFAULT, // ウインドウの横幅 CW_USEDEFAULT, // ウインドウの高さ NULL, // 親ウインドウのハンドル NULL, // メニューバーのハンドル hInstance, // インスタンスのハンドル NULL ); // ウインドウ作成のデータ if ( gWnd != NULL ){ funcSetClientSize( gWnd, gWidth, gHeight ); ShowWindow( gWnd, nCmdShow ); UpdateWindow( gWnd ); } return gWnd; } //--[ライブラリ関数]------------------------------------------------------------ //------------------------------------------------ // 記号定数(エラーコード) //------------------------------------------------ #define ERRCODE_SUCCESS (0) #define ERRCODE_SCREEN (-1) #define ERRCODE_WINREG (-2) #define ERRCODE_CREATE (-3) //------------------------------------------------ // 記号定数(エラー文字列) //------------------------------------------------ #define ERRMSG_SCREEN TEXT("スクリーン・サイズが設定できません。") #define ERRMSG_WINREG TEXT("ウインドウ・クラスが登録できません。") #define ERRMSG_CREATE TEXT("ウインドウが作成できません。") #define ERRMSG_FATAL TEXT("不明なエラー・コードがセットされてます。(%ld)") //------------------------------------------------ // メモリ・デバイスコンテキストの作成 //------------------------------------------------ extern HDC GameMainMemDC( HWND hWnd, LONG nWidth, LONG nHeight ) { HDC hDC; HDC hMemDC; HBITMAP hBitmap; // DCコンパチブルの作成 hDC = GetDC( hWnd ); hMemDC = CreateCompatibleDC( hDC ); hBitmap = CreateCompatibleBitmap( hDC, nWidth, nHeight ); SelectObject( hMemDC, hBitmap ); SelectObject( hMemDC, GetStockObject(DC_PEN) ); SelectObject( hMemDC, GetStockObject(DC_BRUSH) ); DeleteObject( hBitmap ); ReleaseDC( hWnd, hDC ); return hMemDC; } //------------------------------------------------ // ゲームのウインドウを初期化 //------------------------------------------------ extern BOOL GameMainInit( LONG nWidth, LONG nHeight, UINT nFPS ) { if ( gWnd == NULL ){ gWnd = NULL; gFPS = nFPS; gPause = FALSE; gWidth = nWidth; gHeight = nHeight; gErrCode = ERRCODE_SUCCESS; return TRUE; } gErrCode = ERRCODE_SCREEN; return FALSE; } //------------------------------------------------ // ゲームのウインドウを作成 //------------------------------------------------ extern BOOL GameMainCreate( HINSTANCE hInstance, LPCTSTR lpClassName, LPCTSTR lpTitleName, INT nCmdShow ) { // ウインドウ・クラスの登録 if ( funcWindowClass(hInstance,lpClassName) == 0 ){ gErrCode = ERRCODE_WINREG; return FALSE; } // ウインドウの作成 if ( funcCreateWindow(hInstance,lpClassName,lpTitleName,nCmdShow) == NULL ){ gErrCode = ERRCODE_CREATE; return FALSE; } return TRUE; } //------------------------------------------------ // ゲームのメインループを処理 //------------------------------------------------ extern LONG GameMainRun( GAMEFUNC fnInit, GAMEFUNC fnTerm, GAMEFUNC fnUpdate, GAMEDRAW fnDraw ) { MSG Msg; TIMECAPS Caps; DWORD dwTime; HDC hMemDC; // ゲームの初期化 fnInit( gWnd ); timeGetDevCaps( &Caps, sizeof(TIMECAPS) ); timeBeginPeriod( Caps.wPeriodMin ); dwTime = timeGetTime(); hMemDC = (HDC)GetWindowLong( gWnd, GWL_USERDATA ); for ( ; ; ){ if ( PeekMessage(&Msg,NULL,0,0,PM_NOREMOVE) ){ if ( GetMessage(&Msg,NULL,0,0) <= 0 ){ break; } TranslateMessage( &Msg ); DispatchMessage( &Msg ); } else if ( gPause ){ // ゲームの一時停止 dwTime = timeGetTime(); Sleep( 1 ); } else if ( (timeGetTime() - dwTime) >= (1000 / gFPS) ){ dwTime = timeGetTime(); PatBlt( hMemDC, 0, 0, gWidth, gHeight, BLACKNESS ); fnUpdate( gWnd ); // ゲームの進行 fnDraw( hMemDC ); // ゲームの描画 InvalidateRect( gWnd, NULL, FALSE ); UpdateWindow( gWnd ); } else{ Sleep( 1 ); } } // ゲームの後始末 timeEndPeriod( Caps.wPeriodMin ); fnTerm( gWnd ); gWnd = NULL; return Msg.wParam; } //------------------------------------------------ // ゲームのエラー文字列を表示 //------------------------------------------------ extern LONG GameMainErrMsg( HWND hWnd, LPCTSTR lpTitle ) { TCHAR szBuff[ 128 ]; LPTSTR lpForm; UINT nStyle; switch ( gErrCode ){ CASE ERRCODE_SUCCESS: return 0; CASE ERRCODE_SCREEN: lpForm = ERRMSG_SCREEN; nStyle = (MB_OK|MB_ICONERROR); CASE ERRCODE_WINREG: lpForm = ERRMSG_WINREG; nStyle = (MB_OK|MB_ICONERROR); CASE ERRCODE_CREATE: lpForm = ERRMSG_CREATE; nStyle = (MB_OK|MB_ICONWARNING); DEFAULT: lpForm = ERRMSG_FATAL; nStyle = (MB_OK|MB_ICONERROR); } wsprintf( szBuff, lpForm, gErrCode ); MessageBox( hWnd, szBuff, lpTitle, nStyle ); return gErrCode; } //------------------------------------------------------------------------------ // End of GameMainLib.cpp //------------------------------------------------------------------------------
※コメント投稿者のブログIDはブログ作成者のみに通知されます