RPG製作−2.イベント処理とメッセージ表示

 今回は、メッセージを表示するイベントを作ってみます。処理としては、マップ属性mInfo[64][64]の下位8ビットを見て、イベントがあればメッセージを表示するだけなので特に難しい部分はないでしょう。

メッセージの表示

 今回のRPGでは全画面を占有しているので、ダイアログやフレームなどWindowsにあるGUI部品が使えません。メッセージを表示する領域も自分で作る事になります。
 メッセージ表示領域は、384×192ピクセルのサーフェス(メッセージウインドウ)として作成しました。このサーフェスの外側2ピクセルに「枠」を付け、内部にDrawText()でメッセージを描画します。DrawText()では、文字の改行などの処理も行ってくれるので、表示領域に枠の部分を除いたメッセージウインドウ全体を指定してやるだけで良いでしょう。

  // メッセージウインドウ用サーフェス作成
  FillMemory(&ddsdms,0,sizeof(ddsdms));
  ddsdms.dwSize=sizeof(ddsdms);
  ddsdms.dwFlags=DDSD_CAPS| DDSD_WIDTH| DDSD_HEIGHT;
  ddsdms.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN;
  ddsdms.dwWidth=384;
  ddsdms.dwHeight=192;
  lpDD->CreateSurface(&ddsdms,&lpDDSMessage,NULL);

 メッセージウインドウにメッセージを表示する関数messageは以下のようになります。

  void message(LPCTSTR str) { // メッセージ表示

      RECT rec={32,32,512,512};
      HDC hdc;

      // メッセージウインドウをクリア
      lpDDSMessage->Lock(NULL,&ddsdms,DDLOCK_WAIT,NULL);
      LPBYTE lpBuf=(BYTE*)ddsdms.lpSurface; // オフスクリーンサーフェスのポインタ

      FillMemory(lpBuf,384*192,255);
      for (int i=2;i<190;i++)
          FillMemory(lpBuf+2+i*384,380,0);

      lpDDSMessage->Unlock(NULL);

      // メッセージウインドウサーフェスのデバイスコンテキスト取得
      lpDDSMessage->GetDC(&hdc);

      // メッセージ描画
      SetTextColor(hdc,0x00ffffff);
      SetBkMode(hdc,TRANSPARENT);
      DrawText(hdc,str,-1,&recMText,DT_LEFT|DT_WORDBREAK);
      lpDDSMessage->ReleaseDC(hdc);

      // バックバッファに背景を描画
      lpDDSBack->BltFast(0,0,lpDDSScreen,&recScreen,DDBLTFAST_NOCOLORKEY);
      // バックバッファにマップを描画
      lpDDSBack->BltFast(32,88,lpDDSMap,&rec,DDBLTFAST_NOCOLORKEY);
      // バックバッファに主人公を描画(透過処理)
      lpDDSBack->BltFast(224+32,224+88,lpDDSChr,&recChr,DDBLTFAST_SRCCOLORKEY);
      // バックバッファにメッセージウインドウを描画
      lpDDSBack->BltFast(48+32,272+88,lpDDSMessage,&recMes,DDBLTFAST_NOCOLORKEY);

      // バックバッファをフリップ
      lpDDSPrimary->Flip(NULL,DDFLIP_WAIT);

  }

メインループとメッセージ処理

 まず、今回はメインループの処理の流れを通常、スクロール中、メッセージ表示中という「状態」に応じて分けてみました。具体的には、現在の状態を示す変数iStateを用意し、その値によって違う関数を呼び出しています。

  while (1) { /* メインループ */

      if (PeekMessage (&msg,NULL,0,0,PM_NOREMOVE)) {

          if (!GetMessage (&msg,NULL,0,0)) // メッセージ処理
              return msg.wParam ;

          TranslateMessage(&msg);
          DispatchMessage(&msg);

      } else
          switch (iState) {

              case 0: // 通常時
                  none();
                  break;

              case 1: // スクロール中
                  scroll();
                  break;

              case 2: // リターンキー入力待ち
                  wait();
                  bewk;

          }

  }

 イベント判定は、通常時(非スクロール時)の最後に移動先(または現在位置)にイベントがあるか調べ、あればイベント処理関数eventを呼び出すようにしました。

  void none(void) { // 通常時

      int kX,kY;

      iDx=32;
      iDy=32;
      iDdy=0;
      iDdy=0;
      kX=0;
      kY=0;

      // カーソルキーで移動
      if (GetAsyncKeyState(VK_UP)<0) {
			
          kY=-1;

          if(mInfo[iX][iY-1]>32767) {

              iY--; // 主人公の位置更新

              iDdx=0; // スクロール方向設定
              iDdy=-iScd;
              kY=0;

              iState=1; // スクロールフラグセット

          }

      } else if (GetAsyncKeyState(VK_RIGHT)<0) {
			
          kX=1;

          if(mInfo[iX+1][iY]>32767) {

              iX++;
              iDdx=iScd;
              iDdy=0;
              kX=0;

              iState=1;

          }

      } else if (GetAsyncKeyState(VK_DOWN)<0) {
			
          kY=1;

          if(mInfo[iX][iY+1]>32767) {

              iY++;
              iDdx=0;
              iDdy=iScd;
              kY=0;

              iState=1;

          }

      } else if (GetAsyncKeyState(VK_LEFT)<0) {

          kX=-1;

          if(mInfo[iX-1][iY]>32767) {

              iX--;
              iDdx=-iScd;
              iDdy=0;
              kX=0;

              iState=1;

          }

      }

  // イベント判定
  if ((mInfo[iX+kX][iY+kY] & 0xff)!=0)
      event(mInfo[iX+kX][iY+kY] & 0xff);

  }

 変数kX, kYはキーが押された方向を保存するために使っています。

  void event(int e) {

      switch (e) {

          case 1:
              message("水です。\n2行目");
              break;

          case 2:
              message(
                "人物1\nテストテストテストテストテストテストテストテストテスト");
              break;

          case 3:
              message("人物2");
              break;

      }

      iState=2; // 入力待ち

  }

プログラム

 カーソルキーで上下左右に移動できます。メッセージウインドウは、リターンキーで閉じ、終了する時にはエスケープキーを押してください。

 プログラムをコンパイルする時には、DirectX5以上のSDKをインストールする必要があります。ソースをダウンロードしたら、拡張子をcppにしてプロジェクトの設定でddraw.libをリンクしてからビルドしてください。

プログラムソース表示

戻る