今回は、戦闘時の「コマンド」を取得するダイアログウインドウを出してみましょう。まだ戦闘シーンも作ってないのに気が早いようですが、この処理が出来れば同様の処理で通常の選択ダイアログも実現出来るのでイベント・戦闘処理の準備が整った事になります。実際、戦闘処理に最低限必要なのは前回のメッセージ表示と今回のコマンド選択ぐらいのものですしね。
 今回のRPGでは、戦闘時のコマンド(攻撃・回復・道具・逃走)をダイアログで選択する事にしました。ダイアログといってもウインドウの上に別のモーダルダイアログを出すのではなく、メインウインドウ上にサブウインドウとして表示する事にします。これは、今回のRPGはキーボードで操作する事を想定しているためウインドウやボタンをマウスでクリックして選択するような方法は不適だからです。
 具体的には、ゲームの初期化の時に128×148ピクセルのサブウインドウを非表示状態で配置しておきます。実際にコマンドを選択する時には、まずウインドウを表示状態にして上下キー入力でコマンドを選択、リターンキーで決定するようにしましょう。
  hwCmd=CreateWindow("CmdWin",hwMain,WS_CHILD|WS_VISIBLE,
    500,340,128,148,hwnd,(HMENU)0,hInst,NULL);
  ShowWindow(hwCmd,SW_HIDE);
これで、メインウインドウの右下に非表示状態でコマンドダイアログを配置しました。続いて、このウインドウが表示された時の処理を定義しましょう。
コマンドダイアログの表示では、まず中を黒く塗りつぶした白い枠を描きます。後は、内部にコマンドの文字列を描いて行くわけですが、現在選択されている文字列の部分は強調したいですね。現在選択されているコマンドを示す変数iCmdを用意して、この変数を見ながら現在選択されている文字列は黄色で描く事にしましょう。ついでに、文字列の背景も灰色にします。選択されているコマンドは、一番上のコマンドを0、一番下つまり4番目のコマンドを3とする番号で保持する事にしました。
以上の事から、コマンドダイアログのウインドウプロシージャ−は以下のようになります。コマンドダイアログが表示されると、このウインドウプロシージャ−でWM_PAINTが処理されウインドウが描画されるわけですね。コマンド選択の処理では、キー入力を監視して上下のカーソルキーが押されたらコマンドの選択を変更するようにしましょう。選択されているコマンド位置が変更されたら、コマンドダイアログを再描画して新しく選択されたコマンドを強調します。
  LRESULT CALLBACK CmdProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
      HDC hdc;
      PAINTSTRUCT ps;
      RECT rec3;
      LPCTSTR lpszCmd[4]={"攻 撃","回 復","道 具","逃 走"};
      int i;
      switch (iMsg) {
          case WM_PAINT: /* メッセージウインドウ描画 */
              hdc=BeginPaint(hwnd,&ps);
              SelectObject(hdc,GetStockObject(BLACK_BRUSH));
              SelectObject(hdc,GetStockObject(WHITE_PEN));
              /* 枠を描画 */
              Rectangle(hdc,0,0,127,147);
              Rectangle(hdc,1,1,126,146);
              SelectObject(hdc,hCmd);
              SetBkMode(hdc,TRANSPARENT);
              for (i=0;i<4;i++) {
                  /* コマンドの表示領域 */
                  rec3.top=2+i*36;
                  rec3.left=2;
                  rec3.bottom=38+i*36;
                  rec3.right=126;
                  if (iCmd==i) { /* 選択コマンドを強調 */
                      /* 背景を塗りつぶす */
                      FillRect(hdc,&rec3,GetStockObject(GRAY_BRUSH));
                      /* コマンドの描画色設定 */
                      SetTextColor(hdc,0x0000ffff);
                  } else {
                      /* 背景を塗りつぶす */
                      FillRect(hdc,&rec3,GetStockObject(BLACK_BRUSH));
                      /* コマンドの描画色設定 */
                      SetTextColor(hdc,0x00ffffff);
                  }
                  /* コマンド文字列描画 */
                  DrawText(hdc,lpszCmd[i],-1,&rec3,DT_CENTER|DT_SINGLELINE|DT_VCENTER);
              }
	
              EndPaint(hwnd,&ps);
          }
      return DefWindowProc(hwnd, iMsg, wParam, lParam) ;
  }
今回のコマンドは4択なので、ループ内で描画する座標を更新しながら選択肢を描きます。座標の設定と背景・テキスト色に注目してください。文字列は124×36ピクセルの領域に描かれますが、その時にそのコマンドが選択されているかどうかで、色を変えているのがポイントです。この描画処理をカーソルが移動されるたびに繰り返せば、ダイアログでカーソルを移動すると移動先のコマンドが強調表示される事になります。
コマンドダイアログを表示して、選択されたコマンドを返す関数は以下のようになります。
  int getCmd(void) { /* コマンド選択 */
      MSG msg;
      iCmd=0; /* コマンド0を選択状態に */
      ShowWindow(hwCmd,SW_SHOW); /* コマンドダイアログ表示 */
      InvalidateRect(hwCmd,NULL,FALSE);
      UpdateWindow (hwCmd); /* 再描画 */
      Sleep(10);
      while(GetAsyncKeyState(VK_RETURN)<0);
      do { /* リターンキー入力を待つ */
          if (PeekMessage (&msg,NULL,0,0,PM_NOREMOVE)) {
              if (!GetMessage (&msg,NULL,0,0)) /* メッセージ処理 */
                  ExitProcess(msg.wParam);
              TranslateMessage(&msg);
              DispatchMessage(&msg);
          }
          Sleep(1);
          if (GetFocus()==hwMain && GetAsyncKeyState(VK_UP)<0 && iCmd>0) {
              iCmd--; /* 選択コマンド変更 */
              InvalidateRect(hwCmd,NULL,FALSE);
              UpdateWindow (hwCmd); /* 再描画 */
              Sleep(150);
          } else if (GetFocus()==hwMain && GetAsyncKeyState(VK_DOWN)<0 && iCmd<3) {
              iCmd++; /* 選択コマンド変更 */
              InvalidateRect(hwCmd,NULL,FALSE);
              UpdateWindow (hwCmd); /* 再描画 */
              Sleep(150);
          }
      } while(!(GetFocus()==hwMain && GetAsyncKeyState(VK_RETURN)<0));
      ShowWindow(hwCmd,SW_HIDE);
      InvalidateRect(hwMain,&recScreen,FALSE);
      UpdateWindow (hwMain); /* 再描画 */
      while(GetAsyncKeyState(VK_RETURN)<0);
      return iCmd;
  }
実行したらカーソルキーで移動してください。リターンキーでコマンド選択ダイアログを出し、選択するとその結果を表示するメッセージウインドウが出てきます。
今回のプログラムではtimeGetTime()を使っているので、ビルドする時にはプロジェクトのリンクにwinmm.libを追加してください。