キーの操作でシップを動かす



キーの操作「2,4,8,6」とその組み合わせでシップを動かします。
以前はシューティングのような動きの早いゲームを Windows で作成することは無謀だったのですが、 ハードの進歩により不可能では無くなってきました。
そこで Windows でシューティングゲームに挑戦してみましょう。
Java Applet で 爆発 が楽しめます。
C#でも同様のプログラム キーをセンス を作成しています。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. シップの描画には BMP Object Class を使います。
    BMP Object Class の詳細は BMP Object Class の基礎 を参照して下さい。
  2. BMP Object Class を使うので Bmp.cpp と Bmp.h をプロジェクトに追加して下さい。
    ID_TIMER はタイマのIDです。
    *Img は BMP Object Class の定義です。
    g_XP と g_YP はシップを描画する座標で、最初は画面下(320,360)から始めます。
    この値は「2,4,8,6」キーとその組み合わせで自由に座標を操作することができます。
        /*****************************************************************/
        /*★ タイマ割り込みでキーをセンスしてシップを動かす    前田 稔 ★*/
        /*****************************************************************/
        #include    <windows.h>
        #include    "Shoot.h"
        #define     SAFE_DELETE(p)  { if (p) { delete (p);     (p)=NULL; } }
        #define     SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
        #define     ID_TIMER    (WM_APP + 0)
    
        BMP         *Img= NULL;
        long        g_XP= 320;
        long        g_YP= 360;
        
  3. WinMain() では、何時ものようにウインドウを表示するだけですが、背景色と描画の様子を確認するために、 二種類の色で試します。
        WNDCLASS wc = { CS_CLASSDC,WndProc,0L,0L,hInst,NULL,LoadCursor(NULL,IDC_ARROW),
                        (HBRUSH)GetStockObject(LTGRAY_BRUSH),NULL,NAME };
                        //(HBRUSH)GetStockObject(BLACK_BRUSH),NULL,NAME };
        
  4. WM_CREATE: で BMP Class をインスタンス化して、シップの画像を入力します。
    キーのスキャンとシップを表示するタイミングをタイマで設定します。
            case WM_CREATE:
                Img= new SHOOT(hWnd);
                Img->Load("ship.bmp");
                SetTimer(hWnd,ID_TIMER,20,NULL);
                break;
        
  5. WM_PAINT: では g_XP,g_YP の座標にシップを描画するだけです。
    BMP Object Class では、先頭に TRUE を指定すると黒を透明色にして描画します。
    普通の描画と透明色の描画を試してみて下さい。
    透明色の描画は 透明色を使って描画する または 透明色の基礎 を参照して下さい。
            case WM_PAINT:
                hdc= BeginPaint(hWnd,&ps);
                //Img->Show(g_XP,g_YP);
                Img->Show(TRUE,g_XP,g_YP);
                EndPaint(hWnd,&ps);
                break;
        
  6. WM_TIMER: でキーをスキャンしてシップの座標を操作します。
    WM_KEYDOWN: で操作したのでは反応が遅れたり、手を離しても残っているキーがポストされて来ることがあります。
    GetAsyncKeyState() は現在のキー状態をリアルタイムに取得する関数です。
    画面をクリアすると画面がチラツキます。
    クリアしないとチラツキは抑えられるのですが、画像が尾を引きます。
    シップの画像は2ドットずつ移動するので「シップの周りに2ドットの余白」を設けています。
            case WM_TIMER:
                if (wParam == ID_TIMER)
                {   if (GetAsyncKeyState(VK_ESCAPE)<0)
                    {     PostMessage(hWnd,WM_CLOSE,0,0);
                          return 0;
                    }
                    if (GetAsyncKeyState(VK_NUMPAD8)< 0)    g_YP -= 2;
                    if (GetAsyncKeyState(VK_NUMPAD2)< 0)    g_YP += 2;
                    if (GetAsyncKeyState(VK_NUMPAD4)< 0)    g_XP -= 2;
                    if (GetAsyncKeyState(VK_NUMPAD6)< 0)    g_XP += 2;
                }
                //InvalidateRect(hWnd,NULL,FALSE);    //クリアしない
                InvalidateRect(hWnd,NULL,TRUE);     //クリアする
                break;
        
  7. WM_DESTROY: ではタイマを止めて Object Class を開放して下さい。
             case WM_DESTROY:
                KillTimer(hWnd,ID_TIMER);
                SAFE_DELETE(Img);
                PostQuitMessage(0);
                return 0L;
        
  8. メッセージループでは TranslateMessage(&msg) を削除して少しでも軽くします。
    この関数は WM_KEYDOWN: でキーを調べるとき意外は必要ありません。
        while (GetMessage(&msg,NULL,0,0))
        {   //TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        
  9. Windows 10 でも W32 Animation 上下左右の矢印キーでエネミーを動かしています。

【演習】

  1. BMP Object Class に透明色で描画するメンバ関数を追加して下さい。
  2. 画面をクリアする場合とクリアしない場合を試してみて下さい。
  3. 背景色を「白/黒/灰」に切り替えて、画像が尾を引く様子を確認して下さい。
  4. 画面がチラツクのはどんな時でしょう。
  5. チラツキを無くすには、バックバッファを使って描画する方法がベストです。
  6. シップを進行方向に向かって回転しながら描画することも考えてみて下さい。
  7. 装備が異なる複数のシップの画像を用意して、得点やダメージによって切り替える手法も良く使われます。

【メモ】

押されたキーを調べる方法は幾通りかあります。

超初心者のプログラム入門(Win32API C++)