windowsでゲームループを作る。
C/C++とwindowsでゲームを作る時、ウィンドウクラスを登録して、ウィンドウを作って、メッセージループを回して、ウィンドウプロシージャを用意して…と、非常に面倒ですよね。
正直main関数内でそのようなつまらない記述を見たくないわけです。
もっと素直に
- ウィンドウを作って
- ウィンドウが閉じられるまでゲームループを回し、
- 1フレームの処理
を記述したいのです。
int main() { ゲーム用のウィンドウを生成; //ゲームループ while( ウィンドウが閉じられるまで ) { 1フレームの処理; } return 0; }
ということで、以下適当にサンプルを。
main関数はできるだけシンプルに。
#include <windows.h> int main() { //ゲーム用のウィンドウを生成 HWND hwnd = CreateGameWindow( "hoge", 720, 480 ); if( hwnd == nullptr )return 0; //ゲームループ while( !IsClosed( hwnd ) ) //ウィンドウが閉じられるまで { //1フレームの処理 ; //windowsイベントがあればウィンドウプロシージャを実行する。 DoEvents(); } return 0; }
各関数の実装。
面倒だったので、ウィンドウプロシージャも無しの方向で。
/** * 指定サイズのクライアント領域を持つ、ゲーム用の単純なウィンドウを作成する * @param title ウィンドウのタイトルを指定 * @param width クライアント領域の幅を指定 * @param height クライアント領域の高さを指定 * @return 生成したウィンドウのハンドル。失敗時はNULLを返す。 */ HWND CreateGameWindow( const std::string& title, int client_width, int client_height ) { const std::string class_name = "hoge"; const DWORD style = WS_OVERLAPPEDWINDOW & ~( WS_MAXIMIZEBOX | WS_THICKFRAME ); const DWORD exstyle = 0; const HINSTANCE instance = GetModuleHandle( nullptr ); //ウィンドウクラスの登録 WNDCLASSEX wc = { sizeof( WNDCLASSEX ) }; wc.hInstance = instance; wc.lpszClassName = class_name.c_str(); wc.lpfnWndProc = DefWindowProc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.hIcon = static_cast< HICON >( LoadImage( nullptr, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED ) ); wc.hIconSm = wc.hIcon; wc.hCursor = static_cast< HCURSOR >( LoadImage( nullptr, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED ) ); wc.hbrBackground = static_cast< HBRUSH >( GetStockObject( WHITE_BRUSH ) ); if( !RegisterClassEx( &wc ) )return nullptr; //クライアントサイズからウィンドウサイズを計算 RECT rect = { 0, 0, client_width, client_height }; AdjustWindowRectEx( &rect, style, FALSE, exstyle ); //ウィンドウ生成 HWND hwnd = CreateWindowEx( exstyle, class_name.c_str(), title.c_str(), style, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, nullptr, nullptr, instance, nullptr ); if( hwnd == nullptr )return nullptr; ShowWindow( hwnd, SW_SHOW ); return hwnd; } /** * windowsイベントがあればプロシージャを実行する。 * * @return WM_QUITメッセージを受け取ったかどうか */ bool DoEvents() { MSG msg; for(;;) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { //ウィンドウが閉じられた if( msg.message == WM_QUIT )return false; TranslateMessage( &msg ); DispatchMessage( &msg ); //ウィンドウプロシージャの呼び出し } else { //ゲームループで1フレームの処理を行う return true; } } } /** * ウィンドウが閉じられたか * * @param hwnd ウィンドウハンドル */ bool IsClosed( HWND hwnd ) { return ::IsWindow( hwnd ) == FALSE; }
- ウィンドウが閉じられたかどうか調べる際に、IsWindowだけ問題ないのか
サンプルのダウンロード
- gameloop.zip
- VC++2010ExpressEditionで動作確認。