14:タスク処理を実装する(4)
いよいよタスク処理実装も大詰め。WinMain()にタスク処理ルーチンを組み込む方法と、ゲームオブジェクトをタスクに追加するやりかたについて解説します。続いてタスク処理ですが、これはウィンドウのイベントが発生していないときに実行させるようにしましょう。これはPeekMessage()で返値がNULL、つまり処理するウィンドウイベントがなかった時となります。
ここで少し話題は変わるのですが、デバッグにおいて便利な機能をご紹介します。アクション性の高いゲームであるほど、キャラクターが頻繁に出入りするため、メモリの作成・除去もしきりに行われます。そのため、プログラムの如何によっては消去せずほったらかしにしたままプログラムを終了させてしまう可能性もあります。そういった、メモリリークを通知する関数がVisual C++には用意されています。
方法は至って簡単。#include <crtdbg.h>を宣言して、WinMain()の一番先頭に
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

new
までもが置換されるのを避けるため、DirectX関連のdefineを行った後で追加するように。
/* 省略 */
#include <dxerr9.h>
#include <d3d9.h>
#include <d3dx9.h>
#if _DEBUG
#include <crtdbg.h>
#define new ::new( _NORMAL_BLOCK, __FILE__, __LINE__ )
#endif
#define RELEASE(x) {if(x) x->Release();}
class CGameObject;
/* 省略 */
new
に置き換えてやることで、開発環境がメモリの作成位置を取得できるようになり、メモリリークが発生してもどこに問題があったかを突き止めやすくなります(赤線は執筆者によるもの)。

#include <crtdbg.h>
#include "GameObject.h"
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DESTROY:
PostQuitMessage(NULL);
break;
default:
return (DefWindowProc(hWnd, msg, wParam, lParam));
}
return (0);
}
int APIENTRY _tWinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpszCmdLine, int nCmdShow)
{
#ifdef _DEBUG
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
wc.hIcon = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc; //イベント処理関数を連結
wc.lpszClassName = _T("Game");
wc.lpszMenuName = NULL;
wc.style = NULL;
if(RegisterClass(&wc) == NULL){
return 0;
}
HWND hWnd = CreateWindow(
wc.lpszClassName,
_T("クラスまみれのゲームプログラミング入門"),
WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
NULL, NULL, hInstance, NULL );
CGameObject game;
game.Initialize(hWnd, hInstance);
ShowWindow(hWnd, nCmdShow);
MSG msg;
while(TRUE){
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
if(msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}else{
game.DoAllTasks();
}
}
game.Uninitialize();
return 0;
}