トップ 戻る

ゲームプログラミング練習帳
ビットマップ作成からマップスクロール、イベント処理まで

ゲームスレッドスクロール

 アクションゲームやRPGなど「一定間隔でゲームの進行処理や描画を繰り返す」ゲームをWindowsで開発する場合、「ウインドウに送られてくるメッセージの処理」をどうするかが問題になります。プログラムの構造という観点からは、プログラムの起動後に

  do {

    ゲーム処理

  } while (!終了条件);

 といったループに入り、終了時まで時間を監視しながら処理を行うのがわかりやすいでしょう。ただ、実際にこういった構造のプログラムを作るとウインドウメッセージの処理が行われないので、ウインドウの操作が一切できなくなってしまいます。

 そこで、今回はプログラムの起動時にゲームの処理を行う専用のゲームスレッドを作成し、ゲームの処理をそのスレッドで行う構造のプログラムを作ってみることにします。この方式だと、ゲームスレッド内でループに入ってもメインスレッドでウインドウメッセージが処理されるため、ゲームスレッドでゲームの処理に専念しても上記のような問題は生じません。

ゲームスレッドの構造

 今回作るゲームスレッドはごく単純です。スクロール用のビットマップを作成し、それを表示用ビットマップに上方向にずらしながら描画、さらにウインドウを再描画することで「上スクロール」を行うスレッド関数をスレッド化します。このスレッドは、ウインドウ作成(WM_CREATE)時に作成・起動し、ウインドウ破棄(WM_DESTROY)時に終了するようにしましょう。
 スレッド関数内では、ループに入ってスクロール処理を行い続けますが、終了フラグg_bExitを監視して終了フラグがセットされたら、関数を終了するようにします。終了フラグは、メインプログラムの方でWM_DESTROYメッセージの処理を行う時にセットするようにしました。

 ループ内では、起動時からのミリ秒単位の時間を取得するtimeGetTime()で時間を監視し、16ms秒程度の間隔で処理を繰り返すようにします。

  /* ゲームスレッド */
  DWORD WINAPI gameThread(LPVOID lpArg) {

      ・・・・

      do {

          if (timeGetTime() - g_dwTime > 16) {

              /* 今回の処理時間を記録 */
              g_dwTime = timeGetTime();

              ・・スクロール処理・・

          }

      } while (!g_bExit);

      ・・・・

  }

 今回のスクロール処理は、32*32ピクセルのマップチップ15*15チップ分(480*480ピクセル)の大きさの表示ビットマップと、同じく15*16チップ分(480*512ピクセル)の大きさのスクロールビットマップを作成し、スクロールビットマップを表示ビットマップにずらしながら描画することで上スクロールします。表示ビットマップ、スクロールビットマップは共に32ビットDIBSectionとしました。

 このスレッド関数を、ウインドウのWM_CREATEメッセージ処理時に

  /* ゲームスレッド起動 */
  g_hGameThread = (HANDLE)_beginthreadex(NULL, 0, gameThread, NULL, 0, &g_dwGameThreadID);

 として起動し、WM_DETROYメッセージ処理時に

  /* 終了フラグをセットしてスレッドに終了を指示 */
  g_bExit = TRUE;

  /* ゲームスレッド終了待機 */
  if (WaitForSingleObject(g_hGameThread, 2000) != WAIT_OBJECT_0) {
      TerminateThread(g_hGameThread, 0);
  }

  /* ゲームスレッドのハンドルを閉じる */
  CloseHandle(g_hGameThread);

 のようにして終了します。

プログラム

 起動すると、マップチップを敷き詰めたビットマップをひたすら上スクロール表示します。スレッド関数内の処理時間間隔を変更したりスレッド関数内にいろいろ処理を追加したりして、どの程度の性能が出せるか試してみましょう。

プログラムソース表示


トップ 戻る