windowsでゲームループを作る。(2)〜Windowクラス〜
VC++2010を使い始めたので、出来るだけC++0xの機能を使いつつ、前回(http://d.hatena.ne.jp/setuna-kanata/20100512/1273685558)のプログラムを書き換えていきます。
Windowクラス
まずはHWNDのラッパークラスであるWindowクラスを作ります。今回必要になるメソッドは
- コンストラクタ
- ウィンドウが閉じられたかどうか調べるメソッドIsClosed
- とりあえずIsWindow関数を使用
の2つです。
Window.h
#include <windows.h> /** * HWNDのラッパークラス */ class Window { public: /** * コンストラクタ */ Window( HWND hwnd ); public: /** * ウィンドウが閉じられたか */ bool IsClosed()const{ return ::IsWindow( hwnd ) == FALSE; } private: HWND hwnd; };
Window.cpp
#include "Window.h" /** * コンストラクタ。生成済みのウィンドウハンドルを渡す。 */ Window::Window( HWND hwnd ) : hwnd( hwnd ) { }
Applicationクラス
C#風にwindowsイベントを処理するためにDoEvents関数を作ります。
- windowsイベントを処理するためのメソッドDoEvents
- ゲーム用ウィンドウを生成するメソッドCreateGameWindow
- ウィンドウはstd::shared_ptr< Window >で返す
- 前回同様、面倒なのでウィンドウプロシージャは用意せず、DefWindowProcでデフォルトの処理のみ行う。
Application.h
#include <string> #include <memory> class Window; typedef std::shared_ptr< Window > WindowPtr; class Application { public: /** * メッセージキューにある全てのwindowsイベントを処理する。 */ static bool DoEvents(); /** * 指定サイズのクライアント領域を持つ、ゲーム用の単純なウィンドウを作成する */ static WindowPtr CreateGameWindow( const std::string& title, int client_width, int client_height ); };
Application.cpp
#include "Application.h" #include "Window.h" #include <iostream> /** * メッセージキューにある全てのwindowsイベントを処理する。 * * @return WM_QUITメッセージを受け取ったかどうか */ bool Application::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 title ウィンドウのタイトルを指定 * @param width クライアント領域の幅を指定 * @param height クライアント領域の高さを指定 * @return 生成したWindowクラスへのstd::shared_ptrを返す。失敗時はnullptrを返す。 */ WindowPtr Application::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 ); WindowPtr window( new Window( hwnd ) ); std::cout << "ウィンドウを生成( " << title << "," << client_width << "," << client_height << " )" << std::endl; return window; }
使い方
#include "Application.h" #include "Window.h" /** * エントリーポイント */ int main() { //メモリリークの検出を有効化 // アウトプットウィンドウにメモリリーク時の情報が出力される ::_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); //ゲーム用ウィンドウを生成 WindowPtr window = Application::CreateGameWindow( "hoge", 720, 480 ); if( !window )return 0; //ゲームループ // ウィンドウが閉じられるまで1フレームの処理を繰り返す while( !window->IsClosed() ) { //1フレームの処理 ; //メッセージキューにある全てのwindowsイベントを処理する。 Application::DoEvents(); } return 0; }
サンプルのダウンロード
- framework01.zip
- VC++2010ExpressEditionで動作確認